[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "bin/\nobj/\n.vs\n.vscode\n**/*.Android/**/[Rr]esource.[Dd]esigner.cs\n**/*.Droid/**/[Rr]esource.[Dd]esigner.cs\n**/Android/**/[Rr]esource.[Dd]esigner.cs\n**/Droid/**/[Rr]esource.[Dd]esigner.cs\nmodel.json\nsrc/\nflutter/*\n!flutter/download-flutter.ps1\n*.htm\n*.lock\n*.packages\nflutter/**\n*.csproj.user\n"
  },
  {
    "path": "AST/analyzer.dart",
    "content": "import 'package:analyzer/analyzer.dart';\nimport 'package:analyzer/file_system/physical_file_system.dart';\nimport 'dart:io';\nimport 'dart:async';\nimport 'package:analyzer/dart/ast/ast.dart';\nimport 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/sdk/sdk.dart';\nimport 'package:analyzer/src/file_system/file_system.dart';\nimport 'package:analyzer/src/generated/engine.dart';\nimport 'package:analyzer/src/generated/sdk.dart' show DartSdk;\nimport 'package:analyzer/src/generated/source.dart';\nimport 'package:analyzer/src/generated/source_io.dart';\nimport 'package:analyzer/src/source/source_resource.dart';\n\nimport 'config.dart';\nimport 'signature/frame.dart';\nimport 'naming.dart';\nimport 'packageResolver.dart';\n\nmain() async {\n  // 1) Get all directories and all files\n  var outputPath = Directory('..\\\\FlutterSDK\\\\src');\n\n  print(\"Directory: \" + Config.sourcePath);\n  var contents = await dirContents(Directory(Config.sourcePath));\n\n  PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;\n    if (!Config.IsDartSdkPathAvailable) {\n    print(\"Missing $Config.dartSdkEnvVariableName environment variable\");\n    exit(1);\n  }\n  DartSdk sdk = new FolderBasedDartSdk(\n      resourceProvider, resourceProvider.getFolder(Config.DartSdkPath));\n  var flutterSdk = Config.sourcePath\n      .substring(0, Config.sourcePath.lastIndexOf('\\\\'));\n\n  var resolvers = [\n    new DartUriResolver(sdk),\n    Config.isTestbed ? null : new DartUriResolver(embeddedResolver(resourceProvider, flutterSdk)),\n    new ResourceUriResolver(resourceProvider),\n    Config.isTestbed ? null :packageResolver(\n        resourceProvider, 'flutter', resourceProvider.getFolder(flutterSdk)),\n  ];\n\n  AnalysisContext context = AnalysisEngine.instance.createAnalysisContext()\n    ..sourceFactory = new SourceFactory(resolvers);\n\n  // Clear old output directory\n  if (await outputPath.exists()) await outputPath.delete(recursive: true);\n  await outputPath.create();\n\n  // Iterate trough all files\n  // Each file is transpiled and written as one file with its own namespace\n  // the file contains all classes, interfaces, enums and delegates of the source file\n  for (var item in contents) {\n    FileSystemEntityType type = await FileSystemEntity.type(item.path);\n    if (type == FileSystemEntityType.file && item.path.endsWith('dart')) {\n      print(item.path);\n      Source source = new FileSource(resourceProvider.getFile(item.path));\n      ChangeSet changeSet = new ChangeSet()..addedSource(source);\n      context.applyChanges(changeSet);\n      LibraryElement libElement = context.computeLibraryElement(source);\n      CompilationUnit resolvedUnit =\n          context.resolveCompilationUnit(source, libElement);\n\n      var element = resolvedUnit.declaredElement;\n      var namespaceParts =\n          Naming.namespacePartsFromIdentifier(element.library.identifier);\n      var namespaceDartName =\n          Naming.namespaceFromIdentifier(element.library.identifier);\n      var code = Frame.printNamespace(element, namespaceDartName);\n      \n      var file = new File(\n          \"${outputPath.absolute.path}\\\\${namespaceParts.join(\"\\\\\")}.cs\");\n      if (!await file.exists()) await file.create(recursive: true);\n      await file.writeAsString(code);\n      print(\"Wrote ${file.path} to file.\");\n    }\n  }\n}\n\nFuture<List<FileSystemEntity>> dirContents(Directory directory) async {\n  Completer<List<FileSystemEntity>> completer =\n      new Completer<List<FileSystemEntity>>();\n  var files = <FileSystemEntity>[];\n  print(directory);\n\n  var exists = await directory.exists();\n  \n  if (exists) {\n    var stream = directory\n        .list(recursive: true, followLinks: false)\n        .listen((FileSystemEntity entity) {\n      files.add(entity);\n    });\n\n    stream.onDone(() => completer.complete(files));\n  }\n  else\n  {\n    completer.completeError(\"Directory doesn't exist\");\n  }\n\n  return completer.future;\n}\n"
  },
  {
    "path": "AST/comments.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\n\nclass Comments {\n  static void appendComment(StringBuffer buffer, Element element) {\n    return;\n    var dartComment = element.documentationComment;\n    if (dartComment == null || dartComment == \"\") return;\n\n    buffer.writeln(\"/// <Summary>\");\n    buffer.writeln(dartComment);\n    buffer.writeln(\"/// </Summary>\");\n  }\n}"
  },
  {
    "path": "AST/config.dart",
    "content": "import 'dart:io';\n\nclass Config {\n\n  static const dartSdkEnvVariableName = \"DART_SDK\";\n  static bool includeMethodImplementations = false;\n  static bool includeConstructorImplementations = false;\n  static bool includeFieldImplementations = false;\n  static bool isTestbed = false;\n\n  static String sourcePath = Config.isTestbed ? _testbedFlutterSourcePath : _flutterSourcePath;\n\n  // Path to the flutter src directory\n  static String _flutterSourcePath = Directory('..\\\\flutter\\\\lib\\\\src')\n      .absolute\n      .path\n      .replaceAll('\\\\AST\\\\..', '');\n\n  // This is just a quick test bed, if you want to try out specific\n  // Dart related functionality without running it on the whole transpiler  \n  static String _testbedFlutterSourcePath = Directory('..\\\\testbed')\n      .absolute\n      .path\n      .replaceAll('\\\\AST\\\\..', '');\n\n  static bool IsDartSdkPathAvailable = Platform.environment.containsKey(dartSdkEnvVariableName);\n  \n  // Absolute path to the dart-sdk directory\n  static String DartSdkPath = Platform.environment[dartSdkEnvVariableName];\n  \n  // Root namespace the transpiled namespaces will start with\n  static String rootNamespace = \"FlutterSDK\";\n\n  // Imports that are replaced with .net system or mapping libraries\n  static List<String> ignoredImports = new List<String>()\n    ..add(\"package:typed_data/typed_buffers.dart\")\n    ..add(\"package:collection/collection.dart\")\n    ..add(\"dart:ui\")\n    ..add(\"dart:async\")\n    ..add(\"dart:math\")\n    ..add(\"dart:collection\")\n    ..add(\"dart:developer\")\n    ..add(\"dart:io\")\n    ..add(\"dart:core\")\n    ..add(\"dart:typed_data\")\n    ..add(\"dart:_http\")\n    ..add(\"package:meta/meta.dart\")\n    ..add(\"dart:convert\")\n    ..add(\"dart:isolate\")\n    ..add(\"package:vector_math/vector_math_64.dart\")\n    ..add(\"package:typed_data/typed_buffers.dart;\");\n\n  // Imports that will get added to every class\n  static List<String> defaultImports = new List<String>()\n    ..add(\"System\")\n    ..add(\"FlutterSDK\")\n    ..add(\"FlutterSDK.Widgets.Framework\")\n    ..add(\"System.Net.Http\")\n    ..add(\"FlutterBinding.UI\")\n    ..add(\"System.Collections.Generic\")\n    ..add(\"System.Linq\")\n    ..add(\"System.Diagnostics\")\n    ..add(\"SkiaSharp\")\n    ..add(\"FlutterBinding.Engine.Painting\")\n    ..add(\"static FlutterSDK.Global\")\n    ..add(\"FlutterBinding.Mapping\");\n}\n"
  },
  {
    "path": "AST/implementation/conditionals.dart",
    "content": "import 'package:analyzer/dart/ast/ast.dart';\nimport 'implementation.dart';\n\nclass Conditionals {\n  static String processConditionalExpression(ConditionalExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processSwitchStatement(SwitchStatement statement) {\n    var csharp = \"\";\n\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processSwitchCase(SwitchCase switchCase) {\n    var csharp = \"\";\n\n    for (var entity in switchCase.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processSwitchDefault(SwitchDefault switchDefault) {\n    var csharp = \"\";\n\n    for (var entity in switchDefault.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processContinueStatement(ContinueStatement statement) {\n    var csharp = \"\";\n\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processIfStatement(IfStatement statement) {\n    var csharp = \"\";\n\n    for (var entity in statement.childEntities) {\n      if (entity is Block) Implementation.startCastMapping = true;\n\n      csharp += Implementation.processEntity(entity);\n\n      // Clear cast mapping after BlockImpl - TODO: Could backfire if embedded if statements\n      if (entity is Block) {\n        Implementation.castMapping.clear();\n        Implementation.startCastMapping = false;\n      }\n    }\n    return csharp;\n  }\n}\n"
  },
  {
    "path": "AST/implementation/exceptions.dart",
    "content": "import 'package:analyzer/dart/ast/ast.dart';\nimport 'implementation.dart';\n\nclass Exceptions {\n  static String processTryStatement(TryStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processThrowExpression(ThrowExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processCatchClause(CatchClause clause) {\n    var csharp = \"\";\n    for (var entity in clause.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n}\n"
  },
  {
    "path": "AST/implementation/implementation.dart",
    "content": "import 'package:analyzer/analyzer.dart';\nimport 'package:analyzer/dart/ast/ast.dart';\nimport 'package:analyzer/dart/ast/syntactic_entity.dart';\nimport 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/element/element.dart';\nimport 'package:front_end/src/scanner/token.dart';\nimport '../naming.dart';\nimport '../config.dart';\nimport 'loops.dart';\nimport 'exceptions.dart';\nimport 'literals.dart';\nimport 'conditionals.dart';\n\n/// Provides methods to transpile the body of elements\nclass Implementation {\n  static String MethodBody(FunctionBody body) {\n    if (Config.includeMethodImplementations) {\n      if (body is EmptyFunctionBody) {\n        var parent = body.parent;\n        if (parent is MethodDeclaration &&\n            parent.returnType != null &&\n            parent.returnType.toString() != 'void')\n          return '{ \\nreturn default(${processEntity(parent.returnType)}); \\n}';\n        else\n          return '{ \\n}'; // No code;\n      } else if (body is BlockFunctionBody) {\n        return processBlockFunction(body);\n      } else if (body is ExpressionFunctionBody) {\n        return processExpressionFunction(body);\n      } else {\n        // Nothing comes here, so I have implemented all for now.\n        // But this is here in case something in the future appears\n        // and needs to be accounted for.\n        throw new AssertionError('Function block is not defined');\n      }\n    } else\n      return '{ throw new NotImplementedException(); }';\n  }\n\n  static String processExpressionFunction(ExpressionFunctionBody body) {\n    var rawBody = \"\";\n    for (var child in body.childEntities) {\n      rawBody += processEntity(child);\n    }\n\n    return rawBody + '\\n';\n  }\n\n  static String processBlockFunction(BlockFunctionBody body) {\n    var rawBody = \"\\n\";\n    for (var child in body.childEntities) {\n      if (child is Block) {\n        for (var entity in child.childEntities) {\n          rawBody += processEntity(entity) + \"\\n\";\n        }\n      } else if (child is KeywordToken) {\n        rawBody += child.toString() + \"\\n\";\n      } else if (child is SimpleToken) {\n        rawBody += child.toString() + \"\\n\";\n      } else\n        rawBody += \"\\n// Block Function type not dealt with $child\";\n    }\n\n    return rawBody + \"\\n\";\n  }\n\n  static String processCastMap(SyntacticEntity entity) {\n    var name = entity.toString();\n\n    if (castMapping.containsKey(name)) {\n      startCastMapping = false;\n      // Casting to correct type, as it is inside an IsStatement.\n      var result =\n          '((${Naming.upperCamelCase(castMapping[name])})${processEntity(entity)})';\n      startCastMapping = true;\n      return result;\n    }\n\n    return '';\n  }\n\n  static String processEntity(SyntacticEntity entity) {\n    if (startCastMapping) {\n      var castMap = processCastMap(entity);\n      if (castMap.isNotEmpty) return castMap;\n    }\n\n    if (entity is BeginToken) {\n      return entity.lexeme;\n    } else if (entity is KeywordToken) {\n      return processToken(entity);\n    } else if (entity is SimpleToken) {\n      return entity.lexeme;\n    } else if (entity is SimpleIdentifier) {\n      return processSimpleIdentifier(entity);\n    } else if (entity is ThisExpression) {\n      return processThisExpression(entity);\n    } else if (entity is NullLiteral) {\n      return Literals.processNullLiteral(entity);\n    } else if (entity is DoubleLiteral) {\n      return Literals.processDoubleLiteral(entity);\n    } else if (entity is BooleanLiteral) {\n      return Literals.processBooleanLiteral(entity);\n    } else if (entity is IntegerLiteral) {\n      return Literals.processIntegerLiteral(entity);\n    } else if (entity is SimpleStringLiteral) {\n      return Literals.processSimpleStringLiteral(entity);\n    } else if (entity is ArgumentList) {\n      return processArgumentList(entity);\n    } else if (entity is MapLiteral) {\n      return Literals.processMapLiteral(entity);\n    } else if (entity is PrefixedIdentifier) {\n      return processPrefixedIdentifier(entity);\n    } else if (entity is DeclaredIdentifier) {\n      return processDeclaredIdentifier(entity);\n    } else if (entity is PrefixExpression) {\n      return processPrefixExpression(entity);\n    } else if (entity is AdjacentStrings) {\n      return processAdjacentString(entity);\n    } else if (entity is Label) {\n      return processLabel(entity);\n    } else if (entity is MethodInvocation) {\n      return processMethodInvocation(entity);\n    } else if (entity is FunctionExpression) {\n      return processFunctionExpression(entity);\n    } else if (entity is ParenthesizedExpression) {\n      return processParenthesizedExpression(entity);\n    } else if (entity is IndexExpression) {\n      return processIndexExpression(entity);\n    } else if (entity is BinaryExpression) {\n      return processBinaryExpression(entity);\n    } else if (entity is AwaitExpression) {\n      return processAwaitExpression(entity);\n    } else if (entity is ConditionalExpression) {\n      return Conditionals.processConditionalExpression(entity);\n    } else if (entity is StringInterpolation) {\n      return processStringInterpolation(entity);\n    } else if (entity is InterpolationExpression) {\n      return processInterpolationExpression(entity);\n    } else if (entity is InstanceCreationExpression) {\n      return processInstanceCreationExpression(entity);\n    } else if (entity is ConstructorName) {\n      return processConstructorName(entity);\n    } else if (entity is PropertyAccess) {\n      return processPropertyAccess(entity);\n    } else if (entity is AssignmentExpression) {\n      return processAssignmentExpression(entity);\n    } else if (entity is AssertStatement) {\n      return \"\"; // I just ignore assert statements at the moment\n    } else if (entity is ReturnStatement) {\n      return processReturnStatement(entity);\n    } else if (entity is VariableDeclaration) {\n      return processVariableDeclaration(entity);\n    } else if (entity is VariableDeclarationStatement) {\n      return processVariableDeclarationStatement(entity);\n    } else if (entity is VariableDeclarationList) {\n      return processVariableDeclarationList(entity);\n    } else if (entity is SwitchStatement) {\n      return Conditionals.processSwitchStatement(entity);\n    } else if (entity is SwitchCase) {\n      return Conditionals.processSwitchCase(entity);\n    } else if (entity is BreakStatement) {\n      return entity.toString();\n    } else if (entity is SwitchDefault) {\n      return Conditionals.processSwitchDefault(entity);\n    } else if (entity is ContinueStatement) {\n      return Conditionals.processContinueStatement(entity);\n    } else if (entity is IfStatement) {\n      return Conditionals.processIfStatement(entity);\n    } else if (entity is IsExpression) {\n      return processIsExpression(entity);\n    } else if (entity is CascadeExpression) {\n      return processCascadeExpression(entity);\n    } else if (entity is ExpressionStatement) {\n      return processExpressionStatement(entity);\n    } else if (entity is SuperExpression) {\n      return processSuperExpression(entity);\n    } else if (entity is ThrowExpression) {\n      return Exceptions.processThrowExpression(entity);\n    } else if (entity is WhileStatement) {\n      return Loops.processWhileStatement(entity);\n    } else if (entity is ForEachStatement) {\n      return Loops.processForEachStatement(entity);\n    } else if (entity is ForStatement) {\n      return Loops.processForStatement(entity);\n    } else if (entity is ListLiteral) {\n      return Literals.processListLiteral(entity);\n    } else if (entity is FormalParameterList) {\n      return processFormalParameterList(entity);\n    } else if (entity is TypeArgumentList) {\n      return processTypeArgumentList(entity);\n    } else if (entity is SimpleFormalParameter) {\n      return processSimpleFormalParameter(entity);\n    } else if (entity is FunctionDeclarationStatement) {\n      return processFunctionDeclarationStatement(entity);\n    } else if (entity is TryStatement) {\n      return Exceptions.processTryStatement(entity);\n    } else if (entity is CatchClause) {\n      return Exceptions.processCatchClause(entity);\n    } else if (entity is DoStatement) {\n      return Loops.processDoStatement(entity);\n    } else if (entity is YieldStatement) {\n      return processYieldStatement(entity);\n    } else if (entity is PostfixExpression) {\n      return processPostfixExpression(entity);\n    } else if (entity is AsExpression) {\n      return processAsExpression(entity);\n    } else if (entity is NamedExpression) {\n      return processNamedExpression(entity);\n    } else if (entity is TypeName) {\n      return processTypeName(entity);\n    } else if (entity is Block) {\n      return processBlock(entity);\n    } else if (entity is BlockFunctionBody) {\n      return processBlockFunctionBody(entity);\n    } else if (entity is ExpressionFunctionBody) {\n      return processExpressionFunctionBody(entity);\n    } else if (entity is FunctionExpressionInvocation) {\n      return processFunctionExpressionInvocation(entity);\n    } else if (entity is FunctionDeclaration) {\n      return processFunctionDeclaration(entity);\n    } else if (entity is MapLiteralEntry) {\n      return Literals.processMapLiteralEntry(entity);\n    } else if (entity is Annotation) {\n      return ''; // Just ignoring these, because properties in the element determine these annotations, I don't need to parse them.\n    } else {\n      throw new AssertionError('Unknown entity');\n    }\n  }\n\n  static String processPropertyAccess(PropertyAccess access) {\n    var csharp = \"\";\n    for (var entity in access.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processFunctionDeclaration(FunctionDeclaration declaration) {\n    var csharp = \"\";\n    for (var entity in declaration.childEntities) {\n      csharp += processEntity(entity) + ' ';\n    }\n    return csharp;\n  }\n\n  static String processFunctionExpressionInvocation(\n      FunctionExpressionInvocation invocation) {\n    var csharp = \"\";\n    for (var entity in invocation.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processExpressionFunctionBody(ExpressionFunctionBody body) {\n    var csharp = \"\";\n    for (var entity in body.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processTypeArgumentList(TypeArgumentList list) {\n    if (list.childEntities.length < 2)\n      throw new AssertionError(\n          'There should always be brackets around the arguments.');\n\n    var csharp = list.childEntities\n        .where((f) => f is TypeName)\n        .map((f) => processEntity(f))\n        .join(',');\n\n    var entities = list.childEntities.toList();\n\n    var first = entities[0];\n    var end = entities.last;\n    return '$first$csharp$end';\n  }\n\n  static String processBlockFunctionBody(BlockFunctionBody body) {\n    var csharp = \"\";\n    for (var entity in body.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processSimpleFormalParameter(SimpleFormalParameter parameter) {\n    return parameter.childEntities.map((f) => processEntity(f)).join(' ');\n  }\n\n  static String processFormalParameterList(FormalParameterList list) {\n    var csharp = \"\";\n    var hasParameter = false;\n    for (var entity in list.childEntities) {\n      if (entity.toString() == ')' && hasParameter == true)\n        csharp = csharp.substring(0, csharp.length - 2);\n      csharp += processEntity(entity);\n      if (entity is SimpleFormalParameter) {\n        csharp += ', ';\n        hasParameter = true;\n      }\n    }\n    return csharp;\n  }\n\n  static String processAdjacentString(AdjacentStrings string) {\n    var csharp = \"\";\n    for (var entity in string.childEntities) {\n      csharp += processEntity(entity) + ' + ';\n    }\n\n    if (csharp.length > 3) csharp = csharp.substring(0, csharp.length - 3);\n\n    return csharp;\n  }\n\n  static String processDeclaredIdentifier(DeclaredIdentifier identifier) {\n    var csharp = \"\";\n    for (var entity in identifier.childEntities) {\n      csharp += processEntity(entity) + ' ';\n    }\n    return csharp;\n  }\n\n  static String processLabel(Label label) {\n    var csharp = \"\";\n    for (var entity in label.childEntities) {\n      if (entity is SimpleIdentifier)\ncsharp += Naming.escapeFixedWords(processEntity(entity));\n      else \n        csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processPrefixExpression(PrefixExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processFunctionExpression(FunctionExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n      // TODO: need to find a way when it's only a function expression not an actual method\n      if (entity is FormalParameterList) csharp += ' => ';\n    }\n    return csharp;\n  }\n\n  static String processIndexExpression(IndexExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static Map<String, String> castMapping = new Map<String, String>();\n  static bool startCastMapping = false;\n  static String processIsExpression(IsExpression expression) {\n    var count = expression.childEntities.length;\n    if (count < 3 || count > 4)\n      throw new AssertionError(\n          'Expecting IsExpression to always have 3 or 4 entities');\n\n    castMapping.putIfAbsent(expression.childEntities.elementAt(0).toString(),\n        () => expression.childEntities.elementAt(count - 1).toString());\n\n    var csharp = processEntity(expression.childEntities.elementAt(0));\n\n    csharp += ' is ';\n\n    csharp += processEntity(expression.childEntities.elementAt(count - 1));\n\n    if (count == 4 && expression.childEntities.elementAt(2).toString() == '!')\n      csharp = '!($csharp)';\n    else if (count == 4)\n      throw new AssertionError('Unknown 4 length IsExpression');\n\n    return csharp;\n  }\n\n  static String processCascadeExpression(CascadeExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      // If SimpleIdentifier, then it isn't creating anything or a new assignment\n      // its just a variable, and we can ignore it, because the cascades will\n      // put it in front anyway.\n      if (!(entity is SimpleIdentifier)) csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processFunctionDeclarationStatement(\n      FunctionDeclarationStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processYieldStatement(YieldStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processPostfixExpression(PostfixExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processAsExpression(AsExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processNamedExpression(NamedExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      if (entity is SimpleIdentifier)\n        csharp += Naming.escapeFixedWords(processEntity(entity));\n      else\n        csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processBlock(Block block) {\n    var csharp = \"\";\n    for (var item in block.childEntities) {\n      csharp += processEntity(item) + \"\\n\";\n    }\n    return csharp;\n  }\n\n  static String processToken(KeywordToken keyword) {\n    var newKeyword = keyword.keyword.lexeme;\n\n    if (newKeyword == \"super\") return \"base\";\n    if (newKeyword == \"final\" || newKeyword == 'const')\n      return \"\"; // Rarely an equivalence of final or const inside a method, because flutter has compiled consts, whereas C# does not.\n\n    if (newKeyword == 'is') newKeyword = ' ' + newKeyword;\n    if (newKeyword == 'as') newKeyword = ' ' + newKeyword;\n    if (newKeyword == 'in') newKeyword = ' ' + newKeyword;\n\n    return newKeyword + \" \";\n  }\n\n  static String processVariableDeclaration(VariableDeclaration declaration) {\n    var csharp = \"\";\n    for (var entity in declaration.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processSuperExpression(SuperExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processAwaitExpression(AwaitExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processThisExpression(ThisExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processArgumentList(ArgumentList list) {\n    var csharp = \"\";\n    for (var entity in list.childEntities) {\n      if (csharp.endsWith(', ') && entity.toString() == ')')\n        csharp = csharp.substring(0, csharp.length - 2);\n      csharp += processEntity(entity);\n      if (entity.toString() != '(' && entity.toString() != ')') csharp += ', ';\n    }\n    return csharp;\n  }\n\n  static String processParenthesizedExpression(\n      ParenthesizedExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processInstanceCreationExpression(\n      InstanceCreationExpression expression) {\n    var csharp = \"\";\n    var isNamedConstructor = expression.staticElement.name != \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    \n    // TODO: No such thing as named constructors in C#\n    // Will need to look at Static Method calls without the new.\n    if (!csharp.startsWith('new ') && !isNamedConstructor) \n      csharp = 'new ' + csharp;\n    return csharp;\n  }\n\n  static String processConstructorName(ConstructorName name) {\n    var csharp = \"\";\n    for (var entity in name.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processBinaryExpression(BinaryExpression expression) {\n    var csharp = \"\";\n\n    if (expression.childEntities.length == 3 &&\n        expression.childEntities.elementAt(1).toString() == '??') {\n      var first = expression.childEntities.elementAt(0);\n      var second = expression.childEntities.elementAt(2);\n      if (first is SimpleIdentifier && first.staticType != null &&\n          first.staticType.displayName ==\n              'double') //TODO: Should cover all non-nullable value types\n        return '$first == default(${first.staticType.displayName}) ? $second : $first';\n    }\n\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processReturnStatement(ReturnStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processMethodInvocation(MethodInvocation invocation) {\n    var csharp = \"\";\n\n    if (invocation.isCascaded) {\n      var parentEntity = invocation.parent;\n\n      while (parentEntity != null &&\n          (parentEntity is! VariableDeclaration &&\n              parentEntity is! AssignmentExpression \n              && parentEntity is! CascadeExpression))\n        parentEntity = parentEntity.parent;\n\n      if (parentEntity == null)\n      parentEntity.toString();\n\n      String processedEntity =\n          processEntity(parentEntity.childEntities.toList()[0]);\n\n      csharp += ';\\n' + processedEntity + '.';\n\n      for (var entity in invocation.childEntities) {\n        if (entity.toString() != '..') csharp += processEntity(entity);\n      }\n    } else {\n      for (var entity in invocation.childEntities) {\n        csharp += processEntity(entity);\n      }\n\n      // Change all Split's to return a List instead of array\n      if (invocation.methodName.name == 'split') csharp += '.ToList()';\n    }\n\n    return csharp;\n  }\n\n  static String processSimpleIdentifier(SimpleIdentifier identifier) {\n    var csharp = '';\n\n    // Check if this is directly inside the namespace and was mapped inside the namespace default class\n    if(identifier.staticElement != null && identifier.staticElement.enclosingElement is CompilationUnitElement && !(identifier.staticElement is EnumElementImpl)) {\n      // add the default class to the call\n      var defaultClass = Naming.DefaultClassName(identifier.staticElement.enclosingElement);\n      csharp += defaultClass + \".\";\n    }\n\n    // If the identifier is actually a type.\n    if (identifier.parent is TypeName)\n      return Naming.getFormattedTypeName(identifier.name);\n\n    // Map reserved keywords\n    if (identifier.name == 'event') return '@event';\n    if (identifier.name == 'byte') return '@byte';\n\n    if (identifier.staticElement is ParameterElement) // e.g. child\n    {\n      csharp += identifier.name;\n    } else if (identifier.staticElement\n        is MethodElement) // e.g animate // Can't seem to get MethodMember\n    {\n      csharp += processMethodElement(identifier.staticElement);\n    } else if (identifier.staticElement is EnumElementImpl) {\n      var name = identifier.name;\n      csharp += name;\n    } else if (identifier.staticElement is FunctionElement) {\n      csharp += processFunctionElement(identifier.staticElement);\n    } else if (identifier.staticElement is LocalVariableElement) {\n      csharp += identifier.name;\n    } else if (identifier.staticElement is PropertyAccessorElement) {\n      csharp += processPropertyAccessorElement(identifier.staticElement);\n    } else {\n      var name = identifier.name;\n      if (name == 'runtimeType')\n        csharp += 'GetType()';\n      else\n        csharp += Naming.upperCamelCase(name);\n    }\n    return csharp;\n  }\n\n  static String processPrefixedIdentifier(PrefixedIdentifier identifier) {\n    var csharp = \"\";\n    for (var entity in identifier.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processMethodElement(MethodElement element) {\n    var name = element.displayName;\n\n    if (name == \"toUpperCase\") return \"ToUpper\";\n    if (name == \"toLowerCase\") return \"ToLower\";\n    if (name == \"trimRight\") return \"TrimEnd\";\n    if (name == \"trimLeft\") return \"TrimStart\";\n\n    return Naming.upperCamelCase(name);\n  }\n\n  static String processFunctionElement(FunctionElement element) {\n    return Naming.upperCamelCase(element.displayName);\n  }\n\n  static String processPropertyAccessorElement(\n      PropertyAccessorElement element) {\n    var name = element.displayName;\n\n    if (name == \"inMicroseconds\") return \"InMicroseconds()\";\n    if (name == \"isFinite\") return \"IsFinite()\";\n    if (name == 'runtimeType') return 'GetType()';\n    if (name == 'single') return 'Single()';\n    if (name == 'last') return 'Last()';\n    if (name == 'isEmpty') return 'IsEmpty()';\n\n    if (name == 'length' && element.enclosingElement.displayName == 'List')\n      return 'Count';\n\n    if (name == 'length' && element.enclosingElement.displayName == 'List')\n      return 'Count';\n\n    return Naming.upperCamelCase(name);\n  }\n\n  static String processStringInterpolation(StringInterpolation interpolation) {\n    var csharp = '\\$\"';\n\n    for (var entity in interpolation.childEntities) {\n      if (entity is StringLiteral)\n        csharp += entity.stringValue;\n      else if (entity is InterpolationString)\n        csharp += entity.toString();\n      else if (entity is InterpolationExpression) {\n        var stringValue = '{';\n        for (var item in entity.childEntities) {\n          if (!(item is BeginToken) &&\n              item.toString() != '}' &&\n              item.toString() != '\\$') stringValue += processEntity(item);\n        }\n        csharp += stringValue + '}';\n      } else\n        csharp += '{' + processEntity(entity) + '}';\n    }\n\n    return csharp + '\"';\n  }\n\n  static String processInterpolationExpression(\n      InterpolationExpression expression) {\n    var csharp = \"\";\n    for (var entity in expression.childEntities) {\n      csharp += processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processExpressionStatement(ExpressionStatement statement) {\n    var csharp = \"\";\n\n    for (var entity in statement.childEntities) {\n      csharp += processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processAssignmentExpression(AssignmentExpression expression) {\n    var csharp = \"\";\n    var list = expression.childEntities.toList();\n    if (list.length != 3)\n      throw new AssertionError('Should always have 3 parts');\n\n    var nullCheckAssignment = false;\n    var token = list[1] as SimpleToken;\n    if (token != null && token.lexeme == '??=') nullCheckAssignment = true;\n\n    if (nullCheckAssignment) {\n      var variable = processEntity(list[0]);\n      csharp += variable + ' = (' + variable + ' == null ';\n      csharp += '? ' + processEntity(list[2]) + ' ';\n      csharp += ': ' + variable + ' )';\n    } else {\n      for (var entity in expression.childEntities) {\n        csharp += processEntity(entity);\n      }\n    }\n\n    return csharp;\n  }\n\n  static String processVariableDeclarationStatement(\n      VariableDeclarationStatement statement) {\n    var csharp = \"\";\n\n    for (var entity in statement.childEntities) {\n      csharp += processEntity(entity);\n    }\n\n    return csharp;\n  }\n\n  static String processVariableDeclarationList(VariableDeclarationList list) {\n    var csharp = \"\";\n\n    var type = \"\";\n    for (var entity in list.childEntities) {\n      if (entity is TypeName)\n        type = processEntity(entity);\n      else {\n        csharp += ' ' + processEntity(entity);\n      }\n    }\n\n    if (csharp.contains('='))\n      return \"$type $csharp\";\n    else\n      return \"$type $csharp = default($type)\";\n  }\n\n  static String processTypeName(TypeName name) {\n    var csharp = '';\n    if (name.toString().toLowerCase().contains('valuechanged'))\n    name = name;\n    for (var entity in name.childEntities) csharp += processEntity(entity);\n    return csharp;\n  }\n\n  static String fieldBody(PropertyAccessorElement element) {\n    if (Config.includeFieldImplementations && element != null) {\n      // TODO: this is all messed up anyway\n     \n      var body = element.computeNode();\n      var bodyLines = Naming.tokenToText(body.beginToken, false).split(\"\\n\");\n      var rawBody = bodyLines.map((l) => \"${l}\\n\").join();\n\n      // Transpile logic comes here\n      var transpiledBody = \"throw new NotImplementedException();\";\n      return transpiledBody;\n    } else\n      return 'throw new NotImplementedException();';\n  }\n\n  static String functionBody(FunctionElement element) {\n    // TODO\n    return \"throw new NotImplementedException();\";\n  }\n}\n"
  },
  {
    "path": "AST/implementation/literals.dart",
    "content": "import 'package:analyzer/dart/ast/ast.dart';\nimport 'implementation.dart';\n\nclass Literals {\n  static String processNullLiteral(NullLiteral literal) {\n    var csharp = \"\";\n    for (var entity in literal.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processDoubleLiteral(DoubleLiteral literal) {\n    var csharp = \"\";\n    for (var entity in literal.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processBooleanLiteral(BooleanLiteral literal) {\n    var csharp = \"\";\n    for (var entity in literal.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processIntegerLiteral(IntegerLiteral literal) {\n    var csharp = \"\";\n    for (var entity in literal.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processMapLiteral(MapLiteral literal) {\n    var csharp = \"new Dictionary\";\n    for (var entity in literal.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processMapLiteralEntry(MapLiteralEntry entry) {\n    var csharp = \"\";\n    for (var entity in entry.childEntities) {\n      if (entity.toString() == ':')\n        csharp += ', ';\n      else\n        csharp += Implementation.processEntity(entity);\n    }\n    return '{' + csharp + '}';\n  }\n\n  static String processSimpleStringLiteral(SimpleStringLiteral literal) {\n    var stringValue = literal.toString();\n\n    stringValue = stringValue.substring(1, stringValue.length - 1);\n\n    if (stringValue.length == 1 ||\n        (stringValue.startsWith('\\\\') && stringValue.length == 2))\n      return \"'$stringValue'\";\n    else\n      return '\"$stringValue\"';\n  }\n\n  static String processListLiteral(ListLiteral literal) {\n    var csharp = 'new List';\n    var args = false;\n    for (var entity in literal.childEntities) {\n      if (entity.toString() == '[')\n        csharp += '{';\n      else if (entity.toString() == ']') {\n        var length = args == true ? 2 : 0;\n        csharp = csharp.substring(0, csharp.length - length) + '}';\n      }\n      else if (entity is TypeArgumentList)\n      {\n        csharp += Implementation.processEntity(entity) + '()';\n      } else {\n        csharp += Implementation.processEntity(entity) + ', ';\n        args = true;\n      }       \n    }\n    return csharp;\n  }\n}\n"
  },
  {
    "path": "AST/implementation/loops.dart",
    "content": "import 'package:analyzer/dart/ast/ast.dart';\nimport 'implementation.dart';\n\nclass Loops {\n  static String processForStatement(ForStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processWhileStatement(WhileStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processDoStatement(DoStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n\n  static String processForEachStatement(ForEachStatement statement) {\n    var csharp = \"\";\n    for (var entity in statement.childEntities) {\n      if (entity.toString() == 'for')\n        csharp += 'foreach';\n      else\n        csharp += Implementation.processEntity(entity);\n    }\n    return csharp;\n  }\n}\n"
  },
  {
    "path": "AST/naming.dart",
    "content": "import 'package:analyzer/analyzer.dart';\nimport 'package:analyzer/dart/ast/token.dart';\nimport 'package:analyzer/dart/element/type.dart';\nimport 'package:analyzer/dart/element/element.dart';\n\nimport 'config.dart';\nimport 'types.dart';\n\nclass Naming {\n  static List<String> namespacePartsFromIdentifier(String identifier) {\n    var namespacePath = identifier\n        .replaceAll(\n            \"file:///\" + Config.sourcePath.replaceAll(\"\\\\\", \"/\") + \"/\", \"\")\n        .replaceAll(\".dart\", \"\")\n        .replaceAll(\"package:flutter/src/\", \"\");\n\n    var splittedPath = namespacePath\n        .split('/')\n        .map<String>((part) => getFormattedName(part, NameStyle.UpperCamelCase))\n        .toList();\n    return splittedPath;\n  }\n\n  static String namespaceFromIdentifier(String identifier) {\n    var parts = namespacePartsFromIdentifier(identifier);\n\n    return Config.rootNamespace + \".\" + parts.join(\".\");\n  }\n\n  static String nameWithTypeArguments(\n      ParameterizedType type, bool isInterface) {\n    var name = type.name;\n    name = getFormattedName(name, NameStyle.UpperCamelCase);\n\n    if (isInterface) name = \"I\" + name;\n\n    // TODO: Need to sort this out, so it does it for all, not just this particular one.\n    if (name == 'IObstructingPreferredSizeWidget')\n    {\n      var namespace = namespaceFromIdentifier(type.element.library.identifier);\n      name = namespace + \".\" + name;\n    }\n\n    var typeArguments = new List<String>();\n    for (var argument in type.typeArguments) {\n      typeArguments.add(Types.getDartTypeName(argument));\n    }\n    if (typeArguments.length > 0) {\n      name += \"<${typeArguments.join(\",\")}>\";\n    }\n    return name;\n  }\n\n  static String interfaceTypeName(InterfaceType type) {\n    var name = type.name;\n    name = getFormattedName(name, NameStyle.UpperCamelCase);\n\n    var typeArguments = new List<String>();\n    for (var argument in type.typeArguments) {\n      typeArguments.add(Types.getDartTypeName(argument));\n    }\n    if (typeArguments.length > 0) {\n      name += \"<${typeArguments.join(\",\")}>\";\n    }\n    return name;\n  }\n\n  static String nameWithTypeParameters(\n      TypeParameterizedElement element, bool isInterface) {\n    var name = element.name;\n    name = getFormattedName(name, NameStyle.UpperCamelCase);\n\n    if (isInterface) name = \"I\" + name;\n    var typeArguments = new List<String>();\n    for (var argument in element.typeParameters) {\n      typeArguments.add(getTypeParameterName(argument));\n    }\n    if (typeArguments.length > 0) {\n      name += \"<${typeArguments.join(\",\")}>\";\n    }\n    return name;\n  }\n\n  static String parameterTypeWithTypeParameters(\n      ParameterElement element, bool isInterface) {\n    var name = element.type.name;\n    name = getFormattedName(name, NameStyle.UpperCamelCase);\n    if (isInterface) name = \"I\" + name;\n    var typeArguments = new List<String>();\n    for (var argument in element.typeParameters) {\n      typeArguments.add(getTypeParameterName(argument));\n    }\n    if (typeArguments.length > 0) {\n      name += \"<${typeArguments.join(\",\")}>\";\n    }\n    return name;\n  }\n\n  static String getReturnType(FunctionTypedElement element) {\n    var returnType = element.returnType;\n    var returnName = returnType.displayName;\n    var test = element.computeNode();\n    if (returnType is InterfaceType) {\n      returnName = interfaceTypeName(returnType);\n    } else if (test is MethodDeclaration) {\n      if (test.returnType is TypeName) {\n        var t = test.returnType as TypeName;\n        returnName = t.name.name;\n      }\n    } else if (test is FunctionDeclaration) {\n      if (test.returnType is TypeName) {\n        var t = test.returnType as TypeName;\n        returnName = t.name.name;\n      }\n    }\n\n    var formattedName = getFormattedTypeName(returnName);\n\n    if (!(returnType is TypeParameterType) && returnType.element != null) {\n      var library = returnType.element.library;\n      if (library != null &&\n          !Config.ignoredImports.contains(library.identifier) &&\n          ![\"bool\", \"double\", \"object\", \"void\", \"string\", \"T\"]\n              .contains(formattedName)) {\n        var namespace = namespaceFromIdentifier(library.identifier);\n        formattedName = namespace + \".\" + formattedName;\n      }\n    }\n\n    return formattedName;\n  }\n\n  static String className(InterfaceType type) {\n    var baseClass = nameWithTypeArguments(type, false);\n    if (type.element.library != null &&\n        type.element.library.identifier != null &&\n        !Config.ignoredImports.contains(type.element.library.identifier)) {\n      var namespace = namespaceFromIdentifier(type.element.library.identifier);\n      baseClass = \"${namespace}.${baseClass}\";\n    }\n    return baseClass;\n  }\n\n  static String tokenToText(Token token, bool backwards) {\n    if (token.isEof == true ||\n        token.keyword != null ||\n        (token.isKeywordOrIdentifier == false && backwards)) return \"\";\n\n    var text = token.lexeme;\n    if (backwards) {\n      if (token.previous != null)\n        text += \" \" + tokenToText(token.previous, backwards);\n    } else {\n      if (token.next != null) text += \" \" + tokenToText(token.next, backwards);\n    }\n\n    return text;\n  }\n\n  static String getTypeParameterName(TypeParameterElement element) {\n    String typeName = \"object\";\n\n    if (element.type is InterfaceType) {\n      typeName = interfaceTypeName(element.type as InterfaceType);\n    }\n    typeName = element.type.displayName;\n    return getFormattedTypeName(typeName);\n  }\n\n  // TODO: I think this should be rebuilt and accept DartType\n  // Then work from there.\n  static String getFormattedTypeName(String typeName) {\n    var formattedName = typeName;\n\n    if (formattedName.toLowerCase().startsWith(\"ui.\"))\n      formattedName = formattedName.substring(3, formattedName.length - 3);\n\n    if (formattedName == \"Set\" || formattedName.startsWith('Set<'))\n      formattedName = 'HashSet' + formattedName.substring(3);\n    if (formattedName.startsWith(\"Map\"))\n      formattedName = formattedName.replaceAll(\"Map\", \"Dictionary\");\n\n    switch (formattedName.toLowerCase()) {\n      case \"float8list\":\n      case \"float16list\":\n      case \"float32list\":\n        return \"List<double>\";\n      case \"float64list\":\n        return \"List<float>\";\n      case \"int32list\":\n        return \"List<uint>\";\n      case \"httpclientresponse\":\n        return \"HttpResponseMessage\";\n      case \"shader\":\n        return \"SKShader\";\n      // case \"image\": // This doesn't work properly because there is an Image class in the FlutterSDK. But we do need something here for inside method bodies.\n      //   return \"SKImage\";\n      case \"enginelayer\":\n        return \"NativeEngineLayer\";\n      case \"frameinfo\":\n        return \"SKCodecFrameInfo\";\n      case \"codec\":\n        return \"SKCodec\";\n      case \"void\":\n      case \"bool\":\n      case \"int\":\n      case \"object\":\n      case \"double\":\n      case \"string\":\n        return formattedName.toLowerCase();\n      case \"dynamic\": //TODO: we need to fix this. Dynamic is normally hiding a proper type. (AP - Might have fixed, will have to check later)\n        return \"object\";\n      case \"duration\":\n        return \"TimeSpan\";\n      case \"future<void>\":\n      case \"future<null>\":\n        return \"Future\";\n      // case \"iterable\":\n      //   return \"List\";\n      case \"clip\":\n        return \"FlutterBinding.UI.Clip\";\n      case \"paragraph\":\n        return \"FlutterBinding.UI.Paragraph\";\n      default:\n        formattedName =\n            getFormattedName(formattedName, NameStyle.UpperCamelCase);\n        if (formattedName == \"\")\n          return \"object\";\n        else\n          return formattedName;\n    }\n  }\n\n  static String getFormattedName(String originalName, NameStyle style) {\n    var formattedName = originalName;\n    if (formattedName == null || formattedName.length == 0) {\n      return \"\";\n    } else if (formattedName == \"-\") {\n      formattedName = \"subtractOperator\";\n    } else {\n      // We can't do this for names with namespaces already, since it doesn't quite work.\n      if (!formattedName.contains('.')) {\n        var reAddUnderscore = formattedName.startsWith(\"_\");\n        formattedName = formattedName.replaceAll(\"_\", \"\").replaceAll(\"-\", \"\");\n        if (reAddUnderscore) {\n          formattedName = \"_\" + formattedName;\n        }\n      }\n    }\n    if (style != NameStyle.LeadingUnderscoreLowerCamelCase) {\n      formattedName = escapeFixedWords(formattedName);\n    }\n\n    // rename operators\n    if (formattedName == \"==\") formattedName = \"equals\";\n    if (formattedName == \"~/\") formattedName = \"divideIntegerResultOperator\";\n    if (formattedName == \"*\") formattedName = \"multiplyOperator\";\n    if (formattedName == \"/\") formattedName = \"divideOperator\";\n    if (formattedName == \"%\") formattedName = \"moduloOperator\";\n    if (formattedName == \"+\") formattedName = \"addOperator\";\n    if (formattedName == \"[]\") formattedName = \"indexOfOperator\";\n    if (formattedName == \"[]=\") formattedName = \"insertAtOperator\";\n\n    switch (style) {\n      case NameStyle.LowerCamelCase:\n        formattedName = lowerCamelCase(formattedName);\n        break;\n      case NameStyle.UpperCamelCase:\n        formattedName = upperCamelCase(formattedName);\n        break;\n      case NameStyle.LeadingUnderscoreLowerCamelCase:\n        if (!formattedName.startsWith(\"_\"))\n          formattedName = \"_\" + lowerCamelCase(formattedName);\n        break;\n    }\n    return formattedName;\n  }\n\n  static String lowerCamelCase(String name) {\n    if (name.length == 1) return name;\n\n    var underscore = name.startsWith('_');\n\n    if (underscore) name = name.substring(1);\n\n    var newName = name[0].toLowerCase() + name.replaceRange(0, 1, \"\");\n\n    if (underscore) newName = '_' + newName;\n\n    return newName;\n  }\n\n  static String upperCamelCase(String name) {\n    if (name.length <= 1) return name;\n\n    var underscore = name.startsWith('_');\n\n    if (underscore) name = name.substring(1);\n\n    var newName = name[0].toUpperCase() + name.replaceRange(0, 1, \"\");\n\n    if (underscore) newName = '_' + newName;\n\n    return newName;\n  }\n\n  static String escapeFixedWords(String word) {\n    var lowerName = word.toLowerCase();\n    if ([\n      \"event\",\n      \"object\",\n      \"delegate\",\n      \"byte\",\n      \"fixed\",\n      \"checked\",\n      \"base\",\n      \"decimal\",\n      \"byte\"\n    ].any((x) => lowerName == x))\n      return \"@\" + word;\n    else\n      return word;\n  }\n\n  static String DefaultClassName(CompilationUnitElement element) {\n    var name = element.library.identifier\n            .replaceAll(\".dart\", \"\")\n            .replaceAll(\".g\", \"\")\n            .split(\"/\")\n            .last +\n        \"DefaultClass\";\n    return getFormattedName(name, NameStyle.UpperCamelCase);\n  }\n\n  static String getTopLevelVariableName(TopLevelVariableElement element){\n    var name = element.name;\n    name = name.replaceAll(\"\\$\", \"\");\n    return name;\n  }\n}\n\nenum NameStyle {\n  LowerCamelCase,\n  UpperCamelCase,\n  LeadingUnderscoreLowerCamelCase\n}\n\nenum NameType { Name, Type }\n\nenum VariableType { Field, Parameter }\n"
  },
  {
    "path": "AST/packageResolver.dart",
    "content": "import 'package:analyzer/file_system/file_system.dart' as file_system;\nimport 'package:analyzer/file_system/file_system.dart';\nimport 'package:analyzer/source/embedder.dart';\nimport 'package:analyzer/source/package_map_resolver.dart';\nimport 'package:yaml/yaml.dart';\nimport 'package:package_config/packages.dart' show Packages;\nimport 'package:package_config/packages_file.dart' as pkgfile show parse;\nimport 'package:package_config/src/packages_impl.dart' show MapPackages;\nimport 'dart:io' as io;\nimport 'package:analyzer/src/context/builder.dart';\nimport 'package:analyzer/src/source/package_map_resolver.dart';\nimport 'package:analyzer/src/util/uri.dart';\n\nPackageMapUriResolver packageResolver(\n    ResourceProvider provider, String packageName, Folder folder) {\n  Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>();\n\n  packageMap.putIfAbsent(packageName, () => [folder]);\n\n  var resolver = new PackageMapUriResolver(provider, packageMap);\n\n  return resolver;\n}\n\nEmbedderSdk embeddedResolver(ResourceProvider provider, String projectFolder) {\n  // Find package info.\n  _PackageInfo packageInfo = _findPackages(provider, projectFolder);\n\n  // Process embedders.\n  Map<file_system.Folder, YamlMap> embedderMap =\n      new EmbedderYamlLocator(packageInfo.packageMap).embedderYamls;\n\n  var embedder = new EmbedderSdk(embedderMap);\n\n  return embedder;\n}\n\n_PackageInfo _findPackages(ResourceProvider provider, String projectFolder) {\n  Packages packages;\n  Map<String, List<Folder>> packageMap;\n\n  String packageConfigPath = '$projectFolder\\\\..\\\\.packages';\n  Uri fileUri = new Uri.file(packageConfigPath);\n  try {\n    io.File configFile = new io.File.fromUri(fileUri).absolute;\n    List<int> bytes = configFile.readAsBytesSync();\n    Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);\n    packages = new MapPackages(map);\n    packageMap = _getPackageMap(packages, provider);\n  } catch (e) {\n    throw new AssertionError(\n        'Unable to read package config data from $packageConfigPath: $e');\n  }\n\n  return new _PackageInfo(packages, packageMap);\n}\n\nMap<String, List<file_system.Folder>> _getPackageMap(\n    Packages packages, ResourceProvider provider) {\n  if (packages == null) {\n    return null;\n  }\n\n  Map<String, List<file_system.Folder>> folderMap =\n      new Map<String, List<file_system.Folder>>();\n  var pathContext = provider.pathContext;\n  packages.asMap().forEach((String packagePath, Uri uri) {\n    String path = fileUriToNormalizedPath(pathContext, uri);\n    folderMap[packagePath] = [provider.getFolder(path)];\n  });\n  return folderMap;\n}\n\nclass _PackageInfo {\n  Packages packages;\n  Map<String, List<Folder>> packageMap;\n\n  _PackageInfo(this.packages, this.packageMap);\n}\n"
  },
  {
    "path": "AST/pubspec.yaml",
    "content": "name: analyzer_export\n\ndependencies:\n  analyzer: ^0.33.3"
  },
  {
    "path": "AST/readme.md",
    "content": "# Dart to C# transpiler\n\nTODO Intra\n\n## dev prerequisites\n\nTODO what is needed to build this\n-> Config path must be okay\n\n## Procedure\n\nTODO Writ the steps involved\n\n## Signatures\n\nTODO Details about the signature creation\n\n## Naming\n\nTODO Details about the renaming logic\n\n## Body\n\nTODO Details about the body transpiling"
  },
  {
    "path": "AST/run.bat",
    "content": "dart analyzer.dart\n\npause"
  },
  {
    "path": "AST/serialization.dart",
    "content": "// MIT License\n\n// Copyright (c) 2016 Tobe O\n// https://github.com/thosakwe/json_god\n// Modified 2018 Adam Pedley\n\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport 'dart:mirrors';\nimport 'dart:convert';\nimport 'dart:collection';\n\nconst Symbol hashCodeSymbol = #hashCode;\nconst Symbol runtimeTypeSymbol = #runtimeType;\n\ntypedef Serializer(value, {bool primitiveOnly});\n\nList<Symbol> _findGetters(ClassMirror classMirror) {\n  List<Symbol> result = [];\n\n  classMirror.instanceMembers\n      .forEach((Symbol symbol, MethodMirror methodMirror) {\n    if (methodMirror.isGetter &&\n        !methodMirror.isPrivate &&\n        symbol != hashCodeSymbol &&\n        symbol != runtimeTypeSymbol) {\n      result.add(symbol);\n    }\n  });\n\n  return result;\n}\n\nserialize(value, Serializer serializer, {bool primitiveOnly = false}) {\n  Map result = {};\n  InstanceMirror instanceMirror = reflect(value);\n  ClassMirror classMirror = instanceMirror.type;\n\n  for (Symbol symbol in _findGetters(classMirror)) {\n    String name = MirrorSystem.getName(symbol);\n   \n      var field = instanceMirror.getField(symbol);\n\n      var valueForSymbol = field.reflectee;\n      try {\n        result[name] = serializer(valueForSymbol, primitiveOnly: primitiveOnly);\n      } catch (e) {\n        print('$name caused error ${e.toString}');\n      }\n  }\n\n  return result;\n}\n\nbool _isPrimitive(value) {\n  return value is num || value is bool || value is String || value == null;\n}\n\n/// Serializes any arbitrary Dart datum to JSON. Supports schema validation.\nString serializeModel(value) {\n  var serialized = serializeObject(value);\n  return json.encode(serialized);\n}\n\n/// Transforms any Dart datum into a value acceptable to json.encode.\nserializeObject(value, {bool primitiveOnly = false}) {\n  if (_isPrimitive(value)) {\n    return value;\n  } else if (value is DateTime) {\n    return value.toIso8601String();\n  } else if (value is Iterable) {\n    return value.map(serializeObject).toList();\n  } else if (value is LinkedHashMap) {\n    return serializeMap(value);\n  } else if (value is Map) {\n    return serializeMap(value);\n  } else if (!primitiveOnly) {\n    return serializeNonPrimitiveObject(value);\n  } else {\n    return null; // Last resort\n  }\n}\n\nserializeNonPrimitiveObject(value) {\n  return serializeObject(serialize(value, serializeObject));\n}\n\n/// Recursively transforms a Map and its children into JSON-serializable data.\nMap serializeMap(Map value) {\n  Map outputMap = {};\n\n  value.forEach((key, value) {\n    if (key is String) outputMap[key] = serializeObject(value);\n  });\n  return outputMap;\n}\n"
  },
  {
    "path": "AST/signature/classes.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/dart/element/type.dart';\n\nimport '../comments.dart';\nimport '../naming.dart';\nimport 'constructors.dart';\nimport 'fields.dart';\nimport 'methods.dart';\n\nclass Classes {\n  static String printClass(ClassElement element) {\n    var implementWithInterface = element.isMixin || element.isAbstract;\n    var name = Naming.nameWithTypeParameters(element, false);\n\n    // Workaround for classes that are not correctly picked up as interfaces\n    if( [\"PageMetrics\",\"FixedExtentMetrics\",\"GestureArenaEntry\"].contains(name))\n      implementWithInterface = true;\n    \n    var code = new StringBuffer();\n    code.writeln(\"\");\n    Comments.appendComment(code, element);    \n    code.write(\"public \");\n    if (element.isAbstract == true && !implementWithInterface)\n      code.write(\"abstract \");\n    if (element.hasSealed == true) code.write(\"sealed \");\n\n    code.write(\"class ${name}\");\n\n    var generics = '';\n    if (name.contains('<'))\n      generics = name.substring(name.indexOf('<'), name.lastIndexOf('>') + 1);\n\n    // Add base class, interfaces, mixin interfaces\n    var hasBaseClass =\n        element.supertype != null && element.supertype.name != \"Object\";\n    var inheritions = new List<String>();\n    if (hasBaseClass) {\n      inheritions.add(Naming.className(element.supertype));\n    }\n\n    // Add interfaces\n    List<InterfaceType> interfacesToImplement = new List<InterfaceType>(); \n    for (var interface in element.interfaces) {\n      inheritions.add(Naming.nameWithTypeArguments(interface, true));\n      if (interface.element.isValidMixin == false)\n        interfacesToImplement.add(interface);\n    }\n\n    // Add mixin interfaces\n    for (var mxin in element.mixins) {\n      inheritions.add(Naming.nameWithTypeArguments(mxin, true));\n    }\n\n    if (inheritions.length > 0) code.write(\" : \" + inheritions.join(\",\"));\n\n    code.writeln(\"\\n{\");\n\n    code.writeln(\"#region constructors\");\n\n    // Add constructors\n    for (var constructor in element.constructors) {\n      Constructors.printConstructor(code, constructor, generics);\n    }\n    code.writeln(\"#endregion\\n\");\n\n    // Add fields and methods\n    printFieldsAndMethods(code, element, implementWithInterface);\n\n    //Add Implemented Fields and Methods\n    for (var interface in interfacesToImplement)\n      code.write(interfaceFieldAndMethods(interface, element));\n \n    code.writeln(\"}\");\n    return code.toString();\n  }\n\n  // There are some interfaces that are not valid Mixin's but are used as Mixin's?\n  // Maybe I am missing something?? If I am, this should be removed.\n  static String interfaceFieldAndMethods(InterfaceType interface, ClassElement element)\n  {\n    var code = new StringBuffer();\n    var instanceName = interface.displayName;\n\n    var fieldsToImplement = interface.element.fields.where((x) => !x.isPrivate && \n        element.fields.where((y) => y.displayName == x.displayName).length == 0 );\n    var methodsToImplement = interface.methods.where((x) => !x.isPrivate && element.methods.where((y) => y.displayName == x.displayName).length == 0 );\n    \n    var anyToImplement = methodsToImplement.length > 0\n                        || fieldsToImplement.length > 0;\n\n    if (!anyToImplement)\n      return '';\n      \n    code.writeln('$instanceName _${instanceName}Instance = new $instanceName();');\n   \n    for (var method in methodsToImplement)\n    {\n       var methodName = Methods.getMethodName(method);\n       var signature = Methods.methodSignature(method, null, false, '', null, '', '');\n       var parameterCalls = Methods.printParameterNames(method);\n      \n      code.writeln('public $signature => _${instanceName}Instance.$methodName($parameterCalls);');\n    }\n\n    for (var field in fieldsToImplement)\n    {\n       var typeAndName = Fields.printTypeAndName(field);\n          var fieldName = Fields.getFieldName(field);\n      \n      code.writeln('public $typeAndName => _${instanceName}Instance.$fieldName;');\n    }\n\n    return code.toString();\n  }\n\n  static void printFieldsAndMethods(StringBuffer code, ClassElement element,\n      bool implementWithInterface) {\n   \n    code.writeln(\"#region fields\");\n    // Add fields that are not already handled as implementation overrides\n    for (var field\n        in element.fields) {\n      code.writeln(Fields.printField(field));\n    }\n    code.writeln(\"#endregion\\n\");\n\n    code.writeln(\"#region methods\");\n\n    // Add methods that are not already handled as implementation overrides\n    for (var method in element.methods) {\n      code.writeln(Methods.printMethod(method,\n          Methods.overridesParentBaseMethod(method, element)));\n    }\n    code.writeln(\"#endregion\");\n  }\n \n  static String printMixin(ClassElement element)\n  {\n    var name = Naming.nameWithTypeParameters(element, true);\n    var code = new StringBuffer();\n    code.writeln(\"\");\n\n    var rawName = name.substring(1); // Name without `I` at front\n    var generics = '';\n\n    if (rawName.contains('<'))\n    {\n      generics = rawName.substring(rawName.indexOf('<'));\n      rawName = rawName.substring(0, rawName.indexOf('<'));\n    }\n\n    // Start Mixin Interface\n    code.write(\"public interface $name\");\n\n    // Inherits\n    var mixinInheritance = element.mixins\n                                  .where((x) { return x.displayName != 'Object'; })\n                                  .map((f) { return Naming.nameWithTypeParameters(f.element, true); })\n                                  .join(',');\n    \n    if (mixinInheritance.isNotEmpty)\n      code.write(': $mixinInheritance');\n\n    code.writeln('{}\\n'); \n    // End Mixin Interface\n\n    // Start Instance class    \n    var interfaces = element.interfaces\n                            .where((x) { return x.displayName != 'Object' && x is InterfaceType; })\n                            .map((f) { return Naming.nameWithTypeParameters(f.element, true); })\n                            .join(',');\n\n    code.write('public class ${rawName}$generics'); \n\n    if (mixinInheritance.isNotEmpty)\n    {\n      code.write(': $mixinInheritance');\n      if (interfaces.isNotEmpty)\n        code.write(',$interfaces');\n    }\n    else if (interfaces.isNotEmpty)\n      code.write(':$interfaces');\n\n    code.writeln('{');\n\n    // Fields and Methods\n    \n    // Add fields\n    for (var field\n        in element.fields) {\n      code.writeln(Fields.printField(field));\n    }\n  \n    // Add methods\n    for (var method in element.methods) {\n      code.writeln(Methods.printMethod(method,\n          Methods.overridesParentBaseMethod(method, element)));\n    }    \n\n    // Implement interface based fields and methods (e.g. Dart using an `implements`)\n    for (var interface in element.interfaces\n                            .where((x) { return x.displayName != 'Object' && x is InterfaceType; }))\n    {\n      for (var field in interface.element.fields.where((x) => element.fields.where((y) => y.displayName == x.displayName).length == 0))\n        code.writeln(Fields.printField(field));\n\n      for (var method in interface.element.methods.where((x) => element.methods.where((y) => y.displayName == x.displayName).length == 0))\n        code.writeln(Methods.printMethod(method, false));\n    }\n   \n    code.writeln('}'); // End Instance Class\n\n    // Mixin static extensions class \n    code.writeln('public static class ${rawName}Mixin {');\n\n    // Instance holding for mixins\n    if (generics.isEmpty) // No Generics\n      code.writeln('static System.Runtime.CompilerServices.ConditionalWeakTable<$name, $rawName> _table = new System.Runtime.CompilerServices.ConditionalWeakTable<$name, $rawName>();');\n    else // With generics we can't have an unbounded generic as type definition, so we revert to object's and cast later.\n      code.writeln('static System.Runtime.CompilerServices.ConditionalWeakTable<object, object> _table = new System.Runtime.CompilerServices.ConditionalWeakTable<object, object>();');\n\n    // Get Or Create Value\n    code.writeln('static $rawName$generics GetOrCreate$generics($name instance)');\n    code.writeln('{');\n    code.writeln('if (!_table.TryGetValue(instance, out var value))');\n    code.writeln('{');\n    code.writeln('value = new $rawName$generics();');\n    code.writeln('_table.Add(instance, value);');\n    code.writeln('}');\n    code.writeln('return ($rawName$generics)value;');\n    code.writeln('}');\n\n    // Extension Methods\n\n    // Add Fields\n    for (var field\n        in element.fields.where((x) { return x.isPublic; })) {\n          var typeAndName = Fields.printTypeAndName(field);\n          var fieldName = Fields.getFieldName(field);\n\n      code.writeln('public static ${typeAndName}Property$generics(this $name instance) => GetOrCreate(instance).$fieldName;');\n    }\n\n     // Add Methods\n    for (var method\n        in element.methods.where((x) { return x.isPublic; })) {\n          var methodName = Methods.getMethodName(method);\n          var signature = Methods.methodSignature(method, null, false, '', null, 'this $name instance', generics);\n          var parameterCalls = Methods.printParameterNames(method);\n\n          code.writeln('public static ${signature} => GetOrCreate(instance).$methodName($parameterCalls);');     \n    }\n\n    code.writeln('}'); // End Mixin Class\n\n    return code.toString();\n  }\n\n  static String printInterface(ClassElement element) {\n    var name = Naming.nameWithTypeParameters(element, true);\n    var code = new StringBuffer();\n    code.writeln(\"\");\n    Comments.appendComment(code, element);\n\n    if (element.hasProtected == true || element.isPrivate == true)\n      code.write(\"internal \");\n    if (element.isPublic == true) code.write(\"public \");\n\n    code.write(\"interface ${name}{\\n\");\n\n    for (var method in element.methods\n        .where((method) => method.isPublic || method.hasProtected)) {\n      var baseMethod = Methods.getBaseMethodInClass(method);\n      code.writeln(\n          Methods.methodSignature(baseMethod, method, false) + \";\");\n    }\n\n    for (var field in element.fields\n        .where((field) => field.isPublic || field.hasProtected)) {\n      \n      var baseField = Fields.getBaseFieldInClass(field);\n      code.writeln(Fields.getFieldSignature(baseField));\n    }\n\n    code.writeln(\"}\");\n    return code.toString();\n  }\n}\n"
  },
  {
    "path": "AST/signature/constructors.dart",
    "content": "import 'package:analyzer/analyzer.dart';\nimport 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/element/element.dart';\nimport 'package:analyzer/dart/ast/ast.dart';\nimport '../implementation/implementation.dart';\nimport '../naming.dart';\nimport 'methods.dart';\nimport '../config.dart';\nimport 'package:front_end/src/scanner/token.dart';\n\nclass Constructors {\n  static void printConstructor(\n      StringBuffer code, ConstructorElementImpl constructor, String generics) {\n    if (constructor.enclosingElement is ClassElement) {\n      var isFactory = false;\n      var className = constructor.enclosingElement.name;\n      var constructorName = constructor.name;\n      var callsBaseCtor = constructor.redirectedConstructor != null || (constructor.constantInitializers != null && constructor.constantInitializers.length > 0);\n\n      var parameters = Methods.printParameter(constructor, null, null);\n      // normal constructors do not have any special key chars\n      if (constructorName == '')\n        code.writeln('public ${className}($parameters)');\n      // internal classes start with an underscore in dart\n      else if (constructorName == '_')\n        code.writeln('internal ${className}($parameters)');\n      else // I'm named, hence we are turing into static methods that return an instance\n      {\n        var accessibility = constructorName.startsWith('_') ? 'internal' : 'public';\n        isFactory = true;\n        code.writeln(\n            '$accessibility static ${className}$generics ${Naming.upperCamelCase(constructorName)}($parameters)');\n      }\n\n      // Base class call\n      if (callsBaseCtor && !isFactory) {\n        code.writeln(': base(${getBaseParameters(constructor)})');\n      }\n\n      var instanceName = isFactory ? \"instance\" : \"this\";\n\n      // Fill out Constructor body\n      var node = constructor.computeNode();\n      if (node != null) {\n        var body = '{\\n';\n\n        if (isFactory) {\n          // Insert initialization if this is a factory method\n          body += 'var instance =';\n          if (callsBaseCtor) {\n            var parameters = getBaseParameters(constructor);\n            //TODO Get the correct constructor name in case this class does not call its own constructor!\n            body += 'new ${className}$generics(${parameters});';\n          }          \n          else\n            body += 'new ${className}$generics();';\n        }\n\n        // Add auto assignments if any\n        var autoAssignment = Methods.printAutoParameters(constructor, className,\n            instanceName: instanceName);\n        if (autoAssignment.isNotEmpty) body += autoAssignment;\n\n        // add logic and closing curly brace\n        if (Config.includeConstructorImplementations)\n          body = Implementation.MethodBody(node.body).substring(2);\n        else\n          body += 'throw new NotImplementedException(); }';\n\n        // Normal constructor body\n        code.writeln(body);\n      } else\n        code.writeln('{ }');\n    } else\n      throw new AssertionError(\n          'A constructor is not inside a ClassElement, that should not happen.');\n  }\n\n\n\n  static String getBaseParameters(ConstructorElement constructor) {\n    // Get parameters \n    var parameters = \"\";\n    // TODO: I don't think we auto initialize anything when there are other constantIntializers other than a SuperConstructorInvocation\n    // Need to add the other code into the method body.\n    if (constructor is ConstructorElementImpl && constructor.constantInitializers != null &&\n        constructor.constantInitializers.where((x) => x is SuperConstructorInvocation).length > 0) {\n      // :)\n      var constantInitializer = constructor.constantInitializers.where((x) => x is SuperConstructorInvocation).first;\n      var argumentList = constantInitializer.childEntities\n          .where((x) => x is ArgumentList);\n      if (argumentList != null && argumentList.length > 0) {\n        ArgumentList list = argumentList.firstWhere((x) => x is ArgumentList);\n        int count = 0;\n        parameters = list.childEntities\n            .where((argument) =>\n                argument is! BeginToken && argument is! SimpleToken)\n            .map((argument) {\n              var parameter = Naming.escapeFixedWords(Implementation.processEntity(argument)).trim();\n              if (parameter == 'null' \n                  && constructor.redirectedConstructor != null\n                  && constructor.redirectedConstructor.parameters != null \n                  && constructor.redirectedConstructor.parameters[count].type.displayName == 'T')\n              {\n                  // Can't pass null to generic type in C# (you can in Dart).\n                  parameter = 'default(T)';\n              }\n              count += 1;\n              return parameter;\n               })\n            .join(\",\");\n      }\n    }\n    return parameters;\n  }\n}\n"
  },
  {
    "path": "AST/signature/delegates.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\n\nimport '../naming.dart';\nimport 'methods.dart';\n\nclass Delegates {\n  static String printDelegate(FunctionTypeAliasElement element) { \n    var returnType = Naming.getReturnType(element);\n    var methodName = Naming.nameWithTypeParameters(element, false);\n    var parameter = Methods.printParameter(element, element, null); \n    return \"public delegate ${returnType} ${methodName}(${parameter});\";\n  }\n}\n"
  },
  {
    "path": "AST/signature/fields.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/element/element.dart';\nimport 'package:analyzer/dart/element/type.dart';\nimport 'package:analyzer/src/dart/element/type.dart';\nimport 'package:analyzer/src/dart/element/member.dart';\nimport '../implementation/implementation.dart';\nimport '../naming.dart';\nimport '../types.dart';\n\nclass Fields {\n  static bool containsGenericPart(DartType type) {\n    var element = type.element;\n    if (element is TypeParameterElement) return true;\n    if (type is InterfaceType) {\n      var hasTypedTypeArguments =\n          type.typeArguments.any((argument) => argument is TypeParameterType);\n      if (hasTypedTypeArguments) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  static FieldElement getBaseFieldInClass(FieldElement element) {\n    if (element.enclosingElement == null ||\n        element.enclosingElement.allSupertypes.length == 0) return element;\n\n    FieldElement fieldInSupertype;\n    for (var supertype in (element.enclosingElement.allSupertypes\n          ..addAll(element.enclosingElement.superclassConstraints))\n        .where((st) => st is ClassElement)\n        .cast<ClassElement>()\n        .where((st) => st.fields.length > 0)) {\n      fieldInSupertype = supertype.fields.firstWhere(\n          (field) => field.displayName == element.displayName,\n          orElse: () => null);\n      if (fieldInSupertype != null) {\n        // Found method this method extends from\n        break;\n      }\n    }\n\n    if (fieldInSupertype != null) {\n      return getBaseFieldInClass(fieldInSupertype);\n    } else if (element is FieldMember) {      \n      return element.baseElement;\n    } else\n      return element;\n  }\n\n  static String printField(FieldElement element) {\n    var baseField = getBaseFieldInClass(element);\n    var code = new StringBuffer();\n\n    if (element.hasProtected == true) code.write(\"protected \");\n    if (element.isPublic == true) code.write(\"public \");\n    if (element.isPrivate == true) code.write(\"internal \");\n    if (element.hasOverride == true) code.write(\"new \"); // Until we figure it out properly\n    if (element.hasOverride == false) code.write(\"virtual \");\n\n    // type + name\n    if (containsGenericPart(element.type)) {\n      code.write(printTypeAndName(element));\n    } else {\n      code.write(printTypeAndName(baseField));\n    }\n\n    var hasGetter = element.getter != null;\n    var hasSetter = element.setter != null;\n\n    if (hasGetter || hasSetter) {\n      code.write(\"{\");\n      var implementedGetter = false;\n      // getter\n      if (hasGetter) {\n        var getterNode = element.getter.computeNode();\n        if (getterNode == null)\n          code.write(\"get;\");\n        else {\n          code.write(\"get {${Implementation.fieldBody(element.getter)}}\");\n          implementedGetter = true;\n        }\n      }\n      // setter\n      if (hasSetter) {\n        var setterNode = element.setter.computeNode();\n        if (setterNode == null)\n          code.write(\"set;\");\n        else {\n          code.write(\"set {${Implementation.fieldBody(element.setter)}}\");\n        }\n      } else {\n        if (implementedGetter)\n          code.write(\"set { ${Implementation.fieldBody(element.setter)} }\");\n        else\n          code.write(\"set;\"); // For static auto initialization of variables\n      }\n      code.write(\"}\");\n    } else\n      code.write(\";\");\n\n    return code.toString();\n  }\n\n  static String printImplementedField(\n      FieldElement element,\n      FieldElement overridingElement,\n      InterfaceType implementedClass,\n      String implementedFieldName,\n      ClassElement implementingType,\n      InterfaceType originalMixin) {\n    var code = new StringBuffer();\n\n    var elementForSignature = element;\n\n    // HACK: For some reason, just in Animation and Tween, we want the overridingElement\n    // but everywhere else we want the element. Need to correct this.\n    if (overridingElement != null && overridingElement.type.displayName == 'Animation<double>')\n      elementForSignature = overridingElement;\n\n    // type + name\n    var name = getFieldName(elementForSignature);\n\n    if (name == Naming.nameWithTypeParameters(elementForSignature.enclosingElement, false))\n      name = name + \"Value\";\n\n    if (containsGenericPart(elementForSignature.type)) {\n      var typeParameter = implementedClass.typeParameters.firstWhere((tp) =>\n          elementForSignature.type.displayName.contains(tp.type.displayName));\n      var type = implementedClass.typeArguments[\n          implementedClass.typeParameters.indexOf(typeParameter)];\n     \n     var typeName = type.name;\n    \n     // TODO: Might want to put this through a formatter of some kind\n     if (typeName == 'T' && originalMixin != null)\n      typeName = originalMixin.typeArguments[0].name;\n    \n    code.write(\"${typeName} I$implementedFieldName.$name\");\n   \n    } else {\n      code.write(printTypeAndName(elementForSignature, interfaceName: 'I$implementedFieldName.'));\n    }\n\n    var hasGetter = elementForSignature.getter != null;\n    var hasSetter = elementForSignature.setter != null;\n\n    if (hasGetter || hasSetter) {\n      code.write(\"{\");\n      // getter\n      if (hasGetter) {       \n       \n        code.write(\"get => ${implementedFieldName}.${name};\");\n      }\n      // setter\n      if (hasSetter) {\n        code.write(\"set => ${implementedFieldName}.${name} = value;\");\n      }\n\n      code.write(\"}\");\n    } else\n      code.write(\";\");\n\n    return code.toString();\n  }\n\n  static String getFieldSignature(FieldElement element) {\n    var code = new StringBuffer();\n\n    // type + name\n    code.write(printTypeAndName(element));\n\n    var hasGetter = element.getter != null;\n    var hasSetter = element.setter != null;\n\n    if (hasGetter || hasSetter) {\n      code.write(\"{\");\n      // getter\n      if (hasGetter) {\n        code.write(\"get;\");\n      }\n      // setter\n      if (hasSetter) {\n        code.write(\"set;\");\n      }\n      code.write(\"}\");\n    } else\n      code.write(\";\");\n\n    return code.toString();\n  }\n\n  static String printTypeAndName(FieldElement element, {String interfaceName = ''}) {\n    var name = getFieldName(element);\n    if (name == Naming.nameWithTypeParameters(element.enclosingElement, false))\n      name = name + \"Value\";\n\n    var type = Types.getVariableType(element, VariableType.Field);\n\n    return \"${type} $interfaceName${name}\";\n  }\n\n  static String printImplementedTypeAndName(\n      FieldElement element, ClassElement supertypeThatProvidesField) {\n    var type = Types.getVariableType(element, VariableType.Field);\n    var name = getFieldName(element);\n    if (name == Naming.nameWithTypeParameters(element.enclosingElement, false))\n      name = name + \"Value\";\n    \n    return \"${type} ${name}\";\n  }\n\n  static String getFieldName(FieldElement element) {\n    return Naming.getFormattedName(\n        element.name, NameStyle.UpperCamelCase);\n  }\n}\n"
  },
  {
    "path": "AST/signature/frame.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\n\nimport '../comments.dart';\nimport '../config.dart';\nimport '../types.dart';\nimport 'classes.dart';\nimport '../naming.dart';\nimport 'delegates.dart';\nimport 'functions.dart';\n\nclass Frame {\n  static String printNamespace(\n      CompilationUnitElement element, String namespace) {\n    var code = new StringBuffer();\n    code.writeln(printImports(element));\n\n    code.writeln(\"namespace ${namespace}{\");\n\n    // Add delegates\n    for (var delegate in element.functionTypeAliases) {\n      code.writeln(Delegates.printDelegate(delegate));\n    }\n\n    // Add methods that are not inside a class in dart to a default class in c#\n    var defaultClassName = Naming.DefaultClassName(element);\n    code.writeln(\"internal static class ${defaultClassName}{\");\n    for (var topLevelVariable in element.topLevelVariables) {\n      var type = Types.getDartTypeName(topLevelVariable.type);\n      var name = Naming.getTopLevelVariableName(topLevelVariable);\n      name = Naming.upperCamelCase(name);\n      code.writeln(\"public static $type $name = default(${type});\");\n    }\n\n    for (var function in element.functions) {\n      code.writeln(Functions.printFunction(function));\n    }\n    code.writeln(\"}\");\n\n    // Interfaces for abstract classes\n    for (var type in element.types.where((t) =>\n        t.isAbstract == true && t.isValidMixin == false\n        // Workaround for classes that are not correctly picked up as interfaces\n        ||\n        [\"PageMetrics\", \"FixedExtentMetrics\", \"GestureArenaEntry\"]\n            .contains(t.name))) {\n      code.writeln(Classes.printInterface(type));\n    }\n\n    // Add mixins and their interfaces\n    for (var mxin in element.mixins) {\n      code.writeln(Classes.printMixin(mxin));\n    }\n    // If its possibly a valid Mixin, we have to treat it as a Mixin.\n    for (var mxin in element.types.where((t) => t.isValidMixin == true)) {\n      code.writeln(Classes.printMixin(mxin));\n    }\n\n    // Classes\n    // Where not a valid Mixin, because I already created a class in the Mixin section\n    for (var type in element.types.where((t) => t.isValidMixin == false)) {\n      code.writeln(Classes.printClass(type));\n    }\n    // Enums\n    for (var type in element.enums) {\n      code.writeln(printEnum(type));\n    }\n\n    code.writeln(\"}\");\n    return code.toString();\n  }\n\n  static String printImports(CompilationUnitElement element) {\n    var imports = Config.defaultImports;\n    for (var import in element.enclosingElement.imports\n        .where((i) => i.importedLibrary != null)) {\n      AddImport(import.importedLibrary, imports);\n    }\n\n    // This is a workaround since files in the material\\animated_icons folder are utilizing the \"part of\" dart feature\n    // \"part of\" acts like all files are in the same library and imports are not used here\n    // Since we actually need the usings in c# and cant just put the files in one namespace (that would break other references)\n    // we add the missing usings manually\n    if (element.enclosingElement.identifier\n        .contains(\"material/animated_icons\")) {\n      imports.add(\"FlutterSDK.Material.Animatedicons.Animatedicons\");\n      imports.add(\"FlutterSDK.Material.Animatedicons.Animatediconsdata\");\n    }\n\n    // HACK: Remove Cupertino, while in Alpha\n    return imports\n        .where((x) {\n          return !x.contains('Cupertino');\n        })\n        .map((import) => \"using ${import};\")\n        .join(\"\\n\");\n  }\n\n  static void AddImport(LibraryElement import, List<String> allImports) {\n    var name = import.identifier;\n\n    // Skip imports that should get ignored\n    if (Config.ignoredImports.contains(name)) return;\n\n    if (name.contains(\"package:flutter/\")) {\n      if (import.exportedLibraries.length > 0) {\n        // We need to add all sub-libraries of this library\n        for (var subLibrary in import.exportedLibraries) {\n          AddImport(subLibrary, allImports);\n        }\n      }\n\n      // Skip container imports\n      if (!name.contains(\"package:flutter/src/\")) return;\n\n      // Add the package itself\n      name = name.replaceAll(\"package:flutter/src/\", \"\");\n      name = name.replaceAll(\".dart\", \"\");\n      name = Config.rootNamespace +\n          \".\" +\n          name\n              .split(\"/\")\n              .map((part) =>\n                  Naming.getFormattedName(part, NameStyle.UpperCamelCase))\n              .join(\".\");\n    }\n\n    // Check if import is within the FlutterSDK library and modify the import to use the correct namespace\n    if (import != null &&\n        import.identifier.replaceAll(\"/\", \"\\\\\").contains(Config.sourcePath)) {\n      name = Naming.namespaceFromIdentifier(import.identifier);\n    }\n\n    // Add import if it does not already exist\n    if (!allImports.contains(name)) allImports.add(name);\n  }\n\n  static String printEnum(ClassElement element) {\n    var name = Naming.getFormattedTypeName(element.name);\n    var code = new StringBuffer();\n    code.writeln(\"\");\n    Comments.appendComment(code, element);\n\n    // if (element.hasProtected == true || element.isPrivate == true)\n    //   code.write(\"internal \");\n    // if (element.isPublic == true)\n    // HACK: Making all public for the moment\n    code.write(\"public \");\n\n    code.writeln(\"enum ${name}{\");\n    code.writeln(\"\");\n    for (var value in element.fields.where((e) => e.isEnumConstant)) {\n      Comments.appendComment(code, value);\n      var fieldValue = value.name;\n      fieldValue = Naming.upperCamelCase(fieldValue);\n      fieldValue = Naming.escapeFixedWords(fieldValue);\n      code.writeln(fieldValue + \",\");\n    }\n    code.writeln(\"}\");\n    return code.toString();\n  }\n}\n"
  },
  {
    "path": "AST/signature/functions.dart",
    "content": "import 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/element/type.dart';\n\nimport '../implementation/implementation.dart';\nimport '../naming.dart';\nimport 'methods.dart';\n\nclass Functions {\n  static String printFunction(FunctionElement element) {\n    var code = new StringBuffer();\n    code.write(\"internal static \");\n    code.write(methodSignature(element));\n\n    code.writeln(\"{\");\n    code.writeln(Implementation.functionBody(element));\n    code.writeln(\"}\");\n\n    return code.toString();\n  }\n\n  static String methodSignature(ExecutableElement element) {\n    var methodName = Naming.nameWithTypeParameters(element, false);\n    methodName = Naming.getFormattedName(\n        methodName,\n        element.isPrivate\n            ? NameStyle.LeadingUnderscoreLowerCamelCase\n            : NameStyle.UpperCamelCase);\n\n    var parameter = Methods.printParameter(element, element, null);\n    var returnType = Naming.getReturnType(element);\n\n    if (returnType.contains(\"() → dynamic\")) {\n      var type = element.returnType;\n      if (type is FunctionTypeImpl)\n        returnType = type.newPrune[0].name;\n      else\n        throw new AssertionError('Unaccounted for returnType, please fix.');\n    }\n    return \"${returnType} ${methodName}(${parameter})\";\n  }\n}\n"
  },
  {
    "path": "AST/signature/methods.dart",
    "content": "import 'package:analyzer/src/dart/element/member.dart';\nimport 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/dart/element/type.dart';\nimport '../implementation/implementation.dart';\nimport '../comments.dart';\nimport '../naming.dart';\nimport '../types.dart';\n\nclass Methods {\n  static bool isSameSignature(MethodElement m1, MethodElement m2) {\n    return methodSignature(m1, m1, false) == methodSignature(m2, m2, false);\n  }\n\n  static bool overridesBaseMethod(MethodElement method, ClassElement element) {\n    if (element.methods.any((m) => isSameSignature(m, method)) ||\n        overridesParentBaseMethod(method, element)) return true;\n\n    return false;\n  }\n\n  static MethodElement getBaseMethodInClass(MethodElement element) {\n    if (element.enclosingElement == null ||\n        element.enclosingElement.allSupertypes.length == 0) return element;\n\n    MethodElement methodInSupertype;\n    for (var supertype in element.enclosingElement.allSupertypes\n        .where((st) => st.methods.length > 0)) {\n      methodInSupertype = supertype.methods.firstWhere(\n          (method) => method.displayName == element.displayName,\n          orElse: () => null);\n      if (methodInSupertype != null) {\n        // Found method this method extends from\n        break;\n      }\n    }\n\n    if (methodInSupertype != null) {\n      return getBaseMethodInClass(methodInSupertype);\n    } else if (element is MethodMember) {\n      return element.baseElement;\n    } else\n      return element;\n  }\n\n  static bool overridesParentBaseMethod(\n      MethodElement method, ClassElement element) {\n    for (var superType in element.allSupertypes.where(\n        (st) => st.displayName != \"Object\" && !element.mixins.contains(st))) {\n      if (overridesBaseMethod(method, superType.element)) return true;\n    }\n    return false;\n  }\n\n  static String printMethod(MethodElement element, bool isOverride,\n      [String inheritedType = '']) {\n    // HACK: ignoring all ToString() methods at the moment.\n    if (element.name == 'toString') return \"\";\n\n    var baseMethod = getBaseMethodInClass(element);\n\n    var code = new StringBuffer();\n    code.writeln(\"\");\n    Comments.appendComment(code, element);\n\n    var isOverride = element.hasOverride == true && baseMethod != element;\n\n    if (element.isPublic == true)\n      code.write(\"public \");\n    else if (element.hasProtected == true || (element.isPrivate && isOverride))\n      code.write(\"protected \");\n    else if (element.isPrivate == true) code.write(\"private \");\n    if (isOverride) {\n      // HACK: normally use 'override' but use `new` in case return type mismatch\n      // Because C# doesn't support return type covariance (yet anyway, its a proposed feature).\n      code.write(\"new \");\n    }\n    if (element.hasSealed == true)\n      code.write(\"sealed \");\n    // Add virtual as default key if method is not already an override since all methods are virtual in dart\n    else if (element.hasOverride == false && element.isPrivate == false)\n      code.write(\"virtual \");\n\n    code.write(methodSignature(baseMethod, element, isOverride, inheritedType));\n\n    code.writeln(Implementation.MethodBody(element.computeNode().body));\n\n    // HACK: Covariant type used, hence need to implement the exact interface type\n    // In method bodies, we need to convert and redirect this to the actual method above.\n    var isCovariant = false;\n    for (var parameter in baseMethod.parameters) {\n      if (parameter.isCovariant) isCovariant = true;\n    }\n\n    if (isCovariant &&\n        typesDifferent(element.parameters, baseMethod.parameters)) {\n      code.write(\"public new \");\n\n      code.write(methodSignature(baseMethod, null, isOverride, inheritedType));\n\n      code.writeln(Implementation.MethodBody(element.computeNode().body));\n    }\n\n    return code.toString();\n  }\n\n  static bool typesDifferent(\n      List<ParameterElement> first, List<ParameterElement> other) {\n    if (first.length != other.length) return true;\n\n    var count = 0;\n    for (var item in first) {\n      if ((item.type.displayName != other[count].type.displayName) &&\n          other[count].type.displayName != 'T' &&\n          item.type.displayName != 'T' &&\n          !other[count].type.displayName.contains('<T>') &&\n          !item.type.displayName.contains('<T>')) return true;\n      count += 1;\n    }\n\n    return false;\n  }\n\n  static String printImplementedMethod(\n      MethodElement element,\n      String implementationInstanceName,\n      InterfaceType implementedClass,\n      MethodElement overrideMethod,\n      ClassElement classElement,\n      InterfaceType originalMixin) {\n    var baseMethod = implementedClass.element.isMixin\n        ? element\n        : getBaseMethodInClass(element);\n\n    var name = Naming.nameWithTypeParameters(element, false);\n    var code = new StringBuffer();\n    code.writeln(\"\");\n    Comments.appendComment(code, element);\n\n    if (element.isPublic == true) code.write(\"public \");\n    if (element.hasProtected == true) code.write(\"protected \");\n    if (element.hasSealed == true) code.write(\"sealed \");\n    code.write(\"virtual \");\n\n    code.write(methodSignature(baseMethod, element, false, '', originalMixin));\n\n    if (overrideMethod == null) {\n      code.write(\"{\");\n      if (baseMethod.returnType.displayName != \"void\") code.write(\"return \");\n      code.writeln(\n          \"${implementationInstanceName}.${name}(${baseMethod.parameters.map((p) => Naming.getFormattedName(p.name, NameStyle.LowerCamelCase)).join(\",\")});}\");\n    } else {\n      code.writeln(\n          Implementation.MethodBody(overrideMethod.computeNode().body));\n    }\n\n    return code.toString();\n  }\n\n  static bool containsGenericPart(DartType type) {\n    var element = type.element;\n    if (element is TypeParameterElement) return true;\n    if (type is ParameterElement) {\n      print(\"t\");\n    }\n    return false;\n  }\n\n  static String getMethodName(MethodElement element) {\n    var methodName = Naming.nameWithTypeParameters(element, false);\n    if (methodName ==\n        Naming.nameWithTypeParameters(element.enclosingElement, false))\n      methodName = \"Self\" + methodName;\n\n    methodName = Naming.getFormattedName(\n        methodName,\n        element.isPrivate\n            ? NameStyle.LeadingUnderscoreLowerCamelCase\n            : NameStyle.UpperCamelCase);\n\n    return methodName;\n  }\n\n  static String methodSignature(\n      MethodElement element, MethodElement overridenElement, bool isOverride,\n      [String inheritedType = '',\n      InterfaceType originalMixin = null,\n      String additionalParameter = '',\n      String generics = '']) {\n    var highestMethod = overridenElement;\n\n    if (highestMethod == null) highestMethod = element;\n\n    var methodName = getMethodName(element);\n\n    var parameter = printParameter(element, overridenElement, originalMixin);\n    var returnTypeName = Naming.getReturnType(highestMethod);\n    var returnType = highestMethod.returnType;\n    var typeParameter = \"\";\n\n    // Check if the method has a generic return value\n    if (returnType is TypeParameterElement && overridenElement != null) {\n      returnTypeName = Types.getDartTypeName(overridenElement.returnType);\n    }\n\n    // Check if the method return type has type arguments with generic values\n    if (returnType is InterfaceType) {\n      var hasTypedTypeArguments = returnType.typeArguments\n          .any((argument) => argument is TypeParameterType);\n      if (hasTypedTypeArguments) {\n        returnTypeName = Naming.nameWithTypeArguments(returnType, false);\n      }\n    }\n\n    if (isOverride && returnTypeName == 'T' && inheritedType.isNotEmpty) {\n      returnTypeName = inheritedType;\n    }\n\n    if (additionalParameter.isNotEmpty && parameter.isNotEmpty)\n      additionalParameter += ',';\n\n    // HACK: A single once off hack because I'm messing something up here and don't know what\n    if (returnTypeName == 'Future<E>' && methodName == 'Then<R>')\n      methodName = 'Then<E>';\n\n    // Cheap Hack\n    if (returnTypeName == 'Future<Image>') returnTypeName = 'Future<SKImage>'; \n\n    return \"${returnTypeName} ${methodName}${typeParameter}$generics($additionalParameter${parameter})\";\n  }\n\n  static String printAutoParameters(\n      FunctionTypedElement element, String className,\n      {String instanceName = \"this\"}) {\n    return element.parameters.where((x) {\n      return x.isInitializingFormal == true;\n    }).map((p) {\n      var variableName =\n          Naming.getFormattedName(p.name, NameStyle.UpperCamelCase);\n\n      // I don't really like renaming variables, but not sure what other choice we have atm.\n      if (variableName == className) variableName += 'Value';\n\n      return '$instanceName.$variableName = ' +\n          Naming.getFormattedName(p.name, NameStyle.LowerCamelCase) +\n          ';';\n    }).join('\\n');\n  }\n\n  /// This function returns a comma delimited list that\n  static String printParameterNames(FunctionTypedElement element) {\n    return element.parameters.map((p) {\n      var parameterName =\n          Naming.getFormattedName(p.name, NameStyle.LowerCamelCase);\n      if (parameterName == \"\")\n        parameterName = \"p\" + (element.parameters.indexOf(p) + 1).toString();\n\n      return parameterName;\n    }).join(', ');\n  }\n\n  static String printParameter(FunctionTypedElement method,\n      FunctionTypedElement overridenMethod, InterfaceType originalMixin) {\n    // Parameter\n\n    var highestMethod = overridenMethod;\n\n    if (highestMethod == null) {\n      highestMethod = method;\n    }\n\n    var parameters = highestMethod.parameters.map((p) {\n      // Name\n      var parameterName =\n          Naming.getFormattedName(p.name, NameStyle.LowerCamelCase);\n      if (parameterName == \"\")\n        parameterName = \"p\" + (method.parameters.indexOf(p) + 1).toString();\n\n      var parameterType = Types.getParameterType(p, method, overridenMethod);\n\n      if (parameterType == null) {\n        parameterType = \"object\";\n      }\n\n      if (parameterType == 'T' && originalMixin != null) {\n        if (originalMixin.typeArguments[0].name.isNotEmpty)\n          parameterType = originalMixin.typeArguments[0].name;\n      }\n\n      // This is a workaround, the namespace should be added automatically\n      if (parameterType == 'List<Offset>') parameterType = 'List<FlutterBinding.UI.Offset>';\n\n      var parameterSignature = parameterType + \" \" + parameterName;\n\n      // Add keys\n      // Required\n      if (p.hasRequired || p.toString().contains(\"@required\")) {\n        parameterSignature = \"[NotNull] \" + parameterSignature;\n      }\n\n      // Optional\n      if (p.isOptional) {\n        var defaultValue = \"default(${parameterType})\";\n\n        var unmodifiedDefaultValue = p.defaultValueCode;\n        if (unmodifiedDefaultValue != null &&\n            unmodifiedDefaultValue != \"\" &&\n            (unmodifiedDefaultValue == \"true\" ||\n                unmodifiedDefaultValue == \"false\" // bool\n                ||\n                double.tryParse(unmodifiedDefaultValue) != null)) {\n          // numeric\n          defaultValue = p.defaultValueCode;\n        }\n\n        parameterSignature += \" = ${defaultValue}\";\n      }\n      return parameterSignature;\n    });\n    return parameters == null ? \"\" : parameters.join(\",\");\n  }\n}\n"
  },
  {
    "path": "AST/types.dart",
    "content": "import 'package:analyzer/dart/element/type.dart';\nimport 'package:analyzer/dart/element/element.dart';\nimport 'package:analyzer/src/dart/element/type.dart';\nimport 'package:analyzer/analyzer.dart';\nimport 'package:analyzer/src/dart/element/element.dart';\nimport 'package:analyzer/dart/ast/ast.dart';\nimport 'package:front_end/src/base/syntactic_entity.dart';\nimport 'package:front_end/src/scanner/token.dart';\n\nimport 'config.dart';\nimport 'implementation/implementation.dart';\nimport 'naming.dart';\n\nclass Types {\n  static String getDartTypeName(DartType type) {\n    String typeName = \"object\";\n    if (type is InterfaceType) {\n      typeName = Naming.nameWithTypeArguments(type, false);\n    } else if (type is TypeParameterType) {\n      typeName = type.displayName;\n    }\n    var formattedName = Naming.getFormattedTypeName(typeName);\n\n    if (!(type is TypeParameterType) && type.element != null) {\n      var library = type.element.library;\n      if (library != null &&\n          !Config.ignoredImports.contains(library.identifier) &&\n          formattedName != \"object\") {\n        var namespace = Naming.namespaceFromIdentifier(library.identifier);\n        formattedName = namespace + \".\" + formattedName;\n      }\n    }\n\n    return formattedName;\n  }\n\n  static String getVariableType(VariableElement element, VariableType type) {\n    String typeName = \"object\";\n    var elementType = element.type;\n\n    // Function type\n    if (elementType is FunctionTypeImpl) {\n      return handleFunctionType(elementType);\n      // Interface type\n    } else if (elementType is InterfaceType) {\n      typeName = Naming.nameWithTypeArguments(element.type, false);\n    } else if (elementType is TypeParameterType) {\n      typeName = elementType.displayName;\n    } else if (element.computeNode() != null) {\n      switch (type) {\n        case VariableType.Field:\n          typeName = Naming.tokenToText(\n                  element.computeNode().beginToken.previous, true)\n              .split(\" \")\n              .first;\n          break;\n        case VariableType.Parameter:\n          typeName =\n              Naming.tokenToText(element.computeNode().endToken.previous, true)\n                  .split(\" \")\n                  .last;\n          break;\n      }\n    }\n\n    return addNamespace(elementType, typeName);\n  }\n\n  static String addNamespace(DartType type, String typeName) {\n    var formattedName = Naming.getFormattedTypeName(typeName);\n    var library = type.element.library;\n\n    if (library != null && library.displayName == 'dart.ui'){\n      switch(typeName){\n        case \"Image\":\n        case \"Paint\":\n        case \"Picture\":\n        case \"Vertices\":\n         return \"SK\" + typeName;\n        case \"TextStyle\": \n        case \"PointMode\":\n        case \"RRect\":\n        case \"Paragraph\":\n        case \"Offset\":\n        case \"BlendMode\":\n        case \"Rect\":\n        case \"Color\":\n          return \"FlutterBinding.UI.\" + typeName;\n        case \"List<Offset>\":\n          return \"List<FlutterBinding.UI.Offset>\";\n      }\n    }\n\n    if (library != null && library.displayName == 'dart.ui' && typeName == 'Image')\n    return 'SKImage';\n\n    if (library != null && library.displayName == 'dart.ui' && typeName == 'TextStyle')\n    return 'FlutterBinding.UI.TextStyle';\n    \n    if (!(type is TypeParameterType) &&\n        library != null &&\n        !Config.ignoredImports.contains(library.identifier) &&\n        formattedName != \"object\") {\n      var namespace = Naming.namespaceFromIdentifier(library.identifier);\n      formattedName = namespace + \".\" + formattedName;\n    }\n    return formattedName;\n  }\n\n  static String handleFunctionType(FunctionTypeImpl elementType) {\n    if (elementType.newPrune != null) {\n      // We only expect one newPrune\n      if (elementType.newPrune.length != 1) {\n        throw new AssertionError(\n            'Never accounted for elementType to have more than 1 newPrune value.');\n      }\n\n      var typeName = elementType.newPrune[0].displayName;\n\n      var typeAndNamespace = addNamespace(elementType, typeName);\n\n      if (elementType.typeArguments.length > 0) {\n        var typeParameters = elementType.typeArguments.map((p) {\n          return Naming.getFormattedTypeName(p.displayName);\n        }).join(',');\n        typeAndNamespace = '$typeAndNamespace<${typeParameters}>';\n      }\n\n      return typeAndNamespace;\n    }\n\n    // Type did not have newPrune, resolve the func or action manually\n    var parameterTypes = '';\n    if (elementType.normalParameterTypes == null)\n      throw new AssertionError('Its null');\n    if (elementType.normalParameterTypes != null) {\n      parameterTypes = elementType.normalParameterTypes.map((p) {\n        if (p is InterfaceType) {\n          var type = Naming.getFormattedTypeName(p.name);\n          var typeArguments = p.typeArguments.map((t) {\n            return Naming.getFormattedTypeName(t.displayName);\n          }).join(',');\n          if (typeArguments.isEmpty)\n            return type;\n          else\n            return type + '<$typeArguments>';\n        } else\n          return Naming.getFormattedTypeName(p.displayName);\n      }).join(',');\n    }\n\n    // Remove all spaces\n    parameterTypes = parameterTypes.replaceAll(' ', '');\n\n    if (elementType.returnType is VoidType) {\n      // This is an Action\n      if (parameterTypes.isEmpty)\n        return 'Action';\n      else\n        return 'Action<$parameterTypes>';\n    } else {\n      // This is a Function\n\n      // TODO: really need a single function that can do this recursively for all\n      // return types and parameter types.\n\n      var returnType = elementType.returnType;\n      var returnTypeName = elementType.returnType.name;\n      if (returnType.toString() == 'Future<void>')\n        returnTypeName = 'Future';\n      else if (returnType is InterfaceType) {\n        if (returnType.typeArguments.length > 0) {\n          var types = returnType.typeArguments.map((p) {\n            return Naming.getFormattedTypeName(p.name);\n          }).join(',');\n          returnTypeName += '<$types>';\n        }\n      }\n\n     // if (returnType == 'FutureOr') returnType.toString();\n\n      if (parameterTypes.isNotEmpty && parameterTypes != 'void')\n        return 'Func<$returnTypeName,$parameterTypes>';\n      else\n        return 'Func<$returnTypeName>';\n    }\n  }\n\n  static String getParameterType(\n      ParameterElement parameter,\n      FunctionTypedElement method,\n      FunctionTypedElement overridenMethod) {\n    // Type\n\n    //if (parameterType == 'object' && !parameter.toString().contains('dynamic'))\n    //  parameterType = '';\n\n    // if parameter is generic, we use the parameter signature of the method that got overriden\n    if (parameter.type.element is TypeParameterElement &&\n        overridenMethod != null) {\n      parameter = overridenMethod.parameters[\n          method.parameters.indexWhere((x) => x.name == parameter.name)];\n    }\n\n    var parameterType =\n        getVariableType(parameter, VariableType.Parameter).split(\" \").last;\n\n    if (parameterType == \"@\") {\n      parameterType = \"object\";\n    }\n\n    if (parameterType == 'object' && !(parameter.type is DynamicTypeImpl)) {\n      var computedParameter = parameter.computeNode();\n\n      parameterType = getTypeFromComputedNodeEntities(\n          parameter, computedParameter.childEntities, false);\n    }\n     \n    return parameterType;\n  }\n\n  static String getTypeFromComputedNodeEntities(ParameterElement parameter,\n      Iterable<SyntacticEntity> childEntities, bool isRequired) {\n    // Skip the '@required' key, the c# key will be added later\n    var firstEntityName = childEntities.first.toString();\n    if ([\"@required\", \"covariant\"]\n        .any((ignored) => firstEntityName == ignored)) {\n      childEntities = childEntities.skip(1);\n    }\n\n    // this first element should be the element, that represents the type\n    var expectedTypeEntity = childEntities.elementAt(0);\n\n    // One child entity, parameter might be wrapped\n    if (childEntities.length == 1) {\n      if (expectedTypeEntity is SimpleFormalParameter) {\n        return getTypeFromComputedNodeEntities(\n            parameter, expectedTypeEntity.childEntities, isRequired);\n      } else {\n        throw new AssertionError(\"Parameter uses unexpected type.\");\n      }\n      // Two child entities, type + name\n    } else if (childEntities.length == 2) {\n      if (expectedTypeEntity is TypeName) {\n        // Check if this is a prefixed identifier eg. 'ui.actualType'\n        if (expectedTypeEntity.childEntities.length == 1 &&\n            expectedTypeEntity.childEntities.first is PrefixedIdentifier) {\n          var prefixedIdentifier =\n              expectedTypeEntity.childEntities.first as PrefixedIdentifier;\n          return prefixedIdentifier.childEntities.last.toString();\n        } else\n          return Implementation.processTypeName(expectedTypeEntity);\n      } else {\n        throw new AssertionError(\"Parameter uses unexpected type.\");\n      }\n    }\n\n    // More then two entities, this can have multiple reasons\n\n    // Check if this is an auto assigning parameter (eg. this._aPropertyName)\n    if (expectedTypeEntity is KeywordToken &&\n        expectedTypeEntity.lexeme == \"this\") {\n      // Get the field that is initialized by this parameter and use its type\n      var containingMethod = parameter.enclosingElement as FunctionTypedElement;\n      var containingClass = containingMethod.enclosingElement as ClassElement;\n      var field = containingClass.fields.firstWhere(\n          (f) => f.displayName == parameter.name,\n          orElse: () => null);\n      if (field != null && field is FieldElementImpl) {\n        var computed = field.computeNode();\n        var parent = computed.parent;\n        if (parent is VariableDeclarationList) {\n          var type = parent.type;\n\n          if (type is TypeName) return Implementation.processEntity(type);\n        }\n        return getDartTypeName(field.type);\n      } else {\n        throw new AssertionError(\n            \"Could not find field for initialization parameter.\");\n      }\n      // Check if the extra entities contain the default value\n    } else if (parameter.isOptional) {\n      if (expectedTypeEntity is TypeName) {\n        return Implementation.processTypeName(childEntities.first);\n      } else if (expectedTypeEntity is SimpleFormalParameter) {\n        return getTypeFromComputedNodeEntities(\n            parameter, expectedTypeEntity.childEntities, isRequired);\n      } else {\n        throw new AssertionError(\"Optional parameter uses unexpected type.\");\n      }\n    }\n\n    throw new AssertionError(\n        \"Could not resolve parameter type from computed node.\");\n  }\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at adam.pedley@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n"
  },
  {
    "path": "Flutter.Sample.App/Flutter.Sample.App.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\FlutterSDK\\FlutterSDK.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Flutter.Sample.App/MainPage.cs",
    "content": "﻿namespace Flutter.Sample.App\n{\n    // Left here as a sample of what this may look like\n\n    //static void main() => runApp(new MyApp());\n\n    //public class MyApp : StatelessWidget\n    //{\n    //    // This widget is the root of your application.\n    //    public override Widget build(BuildContext context)\n    //    {\n    //        return new MaterialApp(\n    //          title: \"Flutter Demo\",\n    //          theme: new ThemeData(\n    //            // This is the theme of your application.\n    //            //\n    //            // Try running your application with \"flutter run\". You'll see the\n    //            // application has a blue toolbar. Then, without quitting the app, try\n    //            // changing the primarySwatch below to Colors.green and then invoke\n    //            // \"hot reload\" (press \"r\" in the console where you ran \"flutter run\",\n    //            // or press Run > Flutter Hot Reload in IntelliJ). Notice that the\n    //            // counter didn't reset back to zero; the application is not restarted.\n    //            primarySwatch: Colors.blue\n    //          ),\n    //          home: new MyHomePage(title: \"Flutter Demo Home Page\")\n    //        );\n    //    }\n    //}\n\n    //public class MyHomePage : StatefulWidget\n    //{\n    //    public MyHomePage(string title, Key key = null) : base(key: key)\n    //    {\n    //        this.title = title;\n    //    }\n\n    //    // This widget is the home page of your application. It is stateful, meaning\n    //    // that it has a State object (defined below) that contains fields that affect\n    //    // how it looks.\n\n    //    // This class is the configuration for the state. It holds the values (in this\n    //    // case the title) provided by the parent (in this case the App widget) and\n    //    // used by the build method of the State. Fields in a Widget subclass are\n    //    // always marked \"final\".\n\n    //    public readonly string title;\n    //    public override State createState() => new _MyHomePageState();\n    //}\n\n    //public class _MyHomePageState : State<MyHomePage>\n    //{\n    //    int _counter = 0;\n\n    //    void _incrementCounter()\n    //    {\n    //        setState(() =>\n    //        {\n    //            // This call to setState tells the Flutter framework that something has\n    //            // changed in this State, which causes it to rerun the build method below\n    //            // so that the display can reflect the updated values. If we changed\n    //            // _counter without calling setState(), then the build method would not be\n    //            // called again, and so nothing would appear to happen.\n    //            _counter++;\n    //        });\n    //    }\n\n    //    public override Widget build(BuildContext context)\n    //    {\n    //        // This method is rerun every time setState is called, for instance as done\n    //        // by the _incrementCounter method above.\n    //        //\n    //        // The Flutter framework has been optimized to make rerunning build methods\n    //        // fast, so that you can just rebuild anything that needs updating rather\n    //        // than having to individually change instances of widgets.\n    //        return new Scaffold(\n    //          appBar: new AppBar(\n    //            // Here we take the value from the MyHomePage object that was created by\n    //            // the App.build method, and use it to set our appbar title.\n    //            title: new Text(widget.title)\n    //          ),\n    //          body: new Center(\n    //            // Center is a layout widget. It takes a single child and positions it\n    //            // in the middle of the parent.\n    //            child: new Text(\"Hello World!\")\n    //          )\n    //        );\n    //    }\n    //}\n}\n"
  },
  {
    "path": "Flutter.Sample.Droid/Assets/AboutAssets.txt",
    "content": "Any raw assets you want to be deployed with your application can be placed in\nthis directory (and child directories) and given a Build Action of \"AndroidAsset\".\n\nThese files will be deployed with you package and will be accessible using Android's\nAssetManager, like this:\n\npublic class ReadAsset : Activity\n{\n    protected override void OnCreate (Bundle bundle)\n    {\n        base.OnCreate (bundle);\n\n        InputStream input = Assets.Open (\"my_asset.txt\");\n    }\n}\n\nAdditionally, some Android functions will automatically load asset files:\n\nTypeface tf = Typeface.CreateFromAsset (Context.Assets, \"fonts/samplefont.ttf\");"
  },
  {
    "path": "Flutter.Sample.Droid/Flutter.Sample.Droid.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProductVersion>8.0.30703</ProductVersion>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectGuid>{48483C42-37B1-4258-BD46-8387A4FA71C1}</ProjectGuid>\n    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <TemplateGuid>{122416d6-6b49-4ee2-a1e8-b825f31c79fe}</TemplateGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Flutter.Sample.Droid</RootNamespace>\n    <AssemblyName>Flutter.Sample.Droid</AssemblyName>\n    <FileAlignment>512</FileAlignment>\n    <AndroidApplication>True</AndroidApplication>\n    <AndroidResgenFile>Resources\\Resource.Designer.cs</AndroidResgenFile>\n    <AndroidResgenClass>Resource</AndroidResgenClass>\n    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>\n    <AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>\n    <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>\n    <AndroidManifest>Properties\\AndroidManifest.xml</AndroidManifest>\n    <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>\n    <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>\n    <AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>True</DebugSymbols>\n    <DebugType>portable</DebugType>\n    <Optimize>False</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>\n    <AndroidLinkMode>None</AndroidLinkMode>\n    <EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugSymbols>True</DebugSymbols>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>True</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AndroidManagedSymbols>true</AndroidManagedSymbols>\n    <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>\n    <AndroidLinkMode>SdkOnly</AndroidLinkMode>\n    <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"Mono.Android\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"MainActivity.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Resources\\Resource.Designer.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Properties\\AndroidManifest.xml\" />\n    <None Include=\"Assets\\AboutAssets.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <AndroidResource Include=\"Resources\\layout\\activity_main.axml\">\n      <SubType>Designer</SubType>\n    </AndroidResource>\n    <AndroidResource Include=\"Resources\\values\\colors.xml\" />\n    <AndroidResource Include=\"Resources\\values\\ic_launcher_background.xml\" />\n    <AndroidResource Include=\"Resources\\values\\strings.xml\" />\n    <AndroidResource Include=\"Resources\\values\\styles.xml\" />\n    <AndroidResource Include=\"Resources\\mipmap-anydpi-v26\\ic_launcher.xml\" />\n    <AndroidResource Include=\"Resources\\mipmap-anydpi-v26\\ic_launcher_round.xml\" />\n    <AndroidResource Include=\"Resources\\mipmap-hdpi\\ic_launcher.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-hdpi\\ic_launcher_foreground.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-hdpi\\ic_launcher_round.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-mdpi\\ic_launcher.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-mdpi\\ic_launcher_foreground.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-mdpi\\ic_launcher_round.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xhdpi\\ic_launcher.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xhdpi\\ic_launcher_foreground.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xhdpi\\ic_launcher_round.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxhdpi\\ic_launcher.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxhdpi\\ic_launcher_foreground.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxhdpi\\ic_launcher_round.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxxhdpi\\ic_launcher.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxxhdpi\\ic_launcher_foreground.png\" />\n    <AndroidResource Include=\"Resources\\mipmap-xxxhdpi\\ic_launcher_round.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Xamarin.Android.Support.Design\" Version=\"27.0.2.1\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Flutter.Sample.App\\Flutter.Sample.App.csproj\">\n      <Project>{e0fb1bf8-e32c-4a8a-9ae6-e501cc68f279}</Project>\n      <Name>Flutter.Sample.App</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\Flutter.Shell.Droid\\Flutter.Shell.Droid.csproj\">\n      <Project>{c9e1caa4-53f3-4032-92a0-81f5322d446b}</Project>\n      <Name>Flutter.Shell.Droid</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Xamarin\\Android\\Xamarin.Android.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.\n    Other similar extension points exist, see Microsoft.Common.targets.\n    <Target Name=\"BeforeBuild\">\n    </Target>\n    <Target Name=\"AfterBuild\">\n    </Target>\n  -->\n</Project>"
  },
  {
    "path": "Flutter.Sample.Droid/MainActivity.cs",
    "content": "﻿using Android.App;\nusing Android.OS;\nusing Android.Support.V7.App;\nusing Android.Runtime;\nusing Android.Widget;\n\nnamespace Flutter.Sample.Droid\n{\n    [Activity(Label = \"@string/app_name\", Theme = \"@style/AppTheme\", MainLauncher = true)]\n    public class MainActivity : AppCompatActivity\n    {\n        protected override void OnCreate(Bundle savedInstanceState)\n        {\n            base.OnCreate(savedInstanceState);\n            // Set our view from the \"main\" layout resource\n            SetContentView(Resource.Layout.activity_main);\n        }\n    }\n}"
  },
  {
    "path": "Flutter.Sample.Droid/Properties/AndroidManifest.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \n          android:versionCode=\"1\" \n          android:versionName=\"1.0\" \n          package=\"Flutter.Sample.Droid.Flutter.Sample.Droid\">\n  <uses-sdk android:minSdkVersion=\"21\" android:targetSdkVersion=\"27\" />\n  <application android:allowBackup=\"true\" android:icon=\"@mipmap/ic_launcher\" android:label=\"@string/app_name\" android:roundIcon=\"@mipmap/ic_launcher_round\" android:supportsRtl=\"true\" android:theme=\"@style/AppTheme\">\n  </application>\n</manifest>\n"
  },
  {
    "path": "Flutter.Sample.Droid/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Android.App;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Flutter.Sample.Droid\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Flutter.Sample.Droid\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: ComVisible(false)]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/layout/activity_main.axml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n</RelativeLayout>"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/values/Strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Flutter.Sample.Droid</string>\n    <string name=\"action_settings\">Settings</string>\n</resources>\n"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#2c3e50</color>\n    <color name=\"colorPrimaryDark\">#1B3147</color>\n    <color name=\"colorAccent\">#3498db</color>\n</resources>\n"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#2C3E50</color>\n</resources>"
  },
  {
    "path": "Flutter.Sample.Droid/Resources/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "Flutter.Sample.UWP/App.xaml",
    "content": "﻿<Application\n    x:Class=\"Flutter.Sample.UWP.App\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:Flutter.Sample.UWP\">\n\n</Application>\n"
  },
  {
    "path": "Flutter.Sample.UWP/App.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices.WindowsRuntime;\nusing Windows.ApplicationModel;\nusing Windows.ApplicationModel.Activation;\nusing Windows.Foundation;\nusing Windows.Foundation.Collections;\nusing Windows.UI.Xaml;\nusing Windows.UI.Xaml.Controls;\nusing Windows.UI.Xaml.Controls.Primitives;\nusing Windows.UI.Xaml.Data;\nusing Windows.UI.Xaml.Input;\nusing Windows.UI.Xaml.Media;\nusing Windows.UI.Xaml.Navigation;\n\nnamespace Flutter.Sample.UWP\n{\n    /// <summary>\n    /// Provides application-specific behavior to supplement the default Application class.\n    /// </summary>\n    sealed partial class App : Application\n    {\n        /// <summary>\n        /// Initializes the singleton application object.  This is the first line of authored code\n        /// executed, and as such is the logical equivalent of main() or WinMain().\n        /// </summary>\n        public App()\n        {\n            this.InitializeComponent();\n            this.Suspending += OnSuspending;\n        }\n\n        /// <summary>\n        /// Invoked when the application is launched normally by the end user.  Other entry points\n        /// will be used such as when the application is launched to open a specific file.\n        /// </summary>\n        /// <param name=\"e\">Details about the launch request and process.</param>\n        protected override void OnLaunched(LaunchActivatedEventArgs e)\n        {\n            Frame rootFrame = Window.Current.Content as Frame;\n\n            // Do not repeat app initialization when the Window already has content,\n            // just ensure that the window is active\n            if (rootFrame == null)\n            {\n                // Create a Frame to act as the navigation context and navigate to the first page\n                rootFrame = new Frame();\n\n                rootFrame.NavigationFailed += OnNavigationFailed;\n\n                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)\n                {\n                    //TODO: Load state from previously suspended application\n                }\n\n                // Place the frame in the current Window\n                Window.Current.Content = rootFrame;\n            }\n\n            if (e.PrelaunchActivated == false)\n            {\n                if (rootFrame.Content == null)\n                {\n                    // When the navigation stack isn't restored navigate to the first page,\n                    // configuring the new page by passing required information as a navigation\n                    // parameter\n                    rootFrame.Navigate(typeof(MainPage), e.Arguments);\n                }\n                // Ensure the current window is active\n                Window.Current.Activate();\n            }\n        }\n\n        /// <summary>\n        /// Invoked when Navigation to a certain page fails\n        /// </summary>\n        /// <param name=\"sender\">The Frame which failed navigation</param>\n        /// <param name=\"e\">Details about the navigation failure</param>\n        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)\n        {\n            throw new Exception(\"Failed to load Page \" + e.SourcePageType.FullName);\n        }\n\n        /// <summary>\n        /// Invoked when application execution is being suspended.  Application state is saved\n        /// without knowing whether the application will be terminated or resumed with the contents\n        /// of memory still intact.\n        /// </summary>\n        /// <param name=\"sender\">The source of the suspend request.</param>\n        /// <param name=\"e\">Details about the suspend request.</param>\n        private void OnSuspending(object sender, SuspendingEventArgs e)\n        {\n            var deferral = e.SuspendingOperation.GetDeferral();\n            //TODO: Save application state and stop any background activity\n            deferral.Complete();\n        }\n    }\n}\n"
  },
  {
    "path": "Flutter.Sample.UWP/Flutter.Sample.UWP.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x86</Platform>\n    <ProjectGuid>{F02BD326-5760-4246-9EDC-C41B489E965B}</ProjectGuid>\n    <OutputType>AppContainerExe</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Flutter.Sample.UWP</RootNamespace>\n    <AssemblyName>Flutter.Sample.UWP</AssemblyName>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>\n    <TargetPlatformVersion Condition=\" '$(TargetPlatformVersion)' == '' \">10.0.17763.0</TargetPlatformVersion>\n    <TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>\n    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>\n    <PackageCertificateKeyFile>Flutter.Sample.UWP_TemporaryKey.pfx</PackageCertificateKeyFile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup>\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"App.xaml.cs\">\n      <DependentUpon>App.xaml</DependentUpon>\n    </Compile>\n    <Compile Include=\"MainPage.xaml.cs\">\n      <DependentUpon>MainPage.xaml</DependentUpon>\n    </Compile>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <AppxManifest Include=\"Package.appxmanifest\">\n      <SubType>Designer</SubType>\n    </AppxManifest>\n    <None Include=\"Flutter.Sample.UWP_TemporaryKey.pfx\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"Properties\\Default.rd.xml\" />\n    <Content Include=\"Assets\\LockScreenLogo.scale-200.png\" />\n    <Content Include=\"Assets\\SplashScreen.scale-200.png\" />\n    <Content Include=\"Assets\\Square150x150Logo.scale-200.png\" />\n    <Content Include=\"Assets\\Square44x44Logo.scale-200.png\" />\n    <Content Include=\"Assets\\Square44x44Logo.targetsize-24_altform-unplated.png\" />\n    <Content Include=\"Assets\\StoreLogo.png\" />\n    <Content Include=\"Assets\\Wide310x150Logo.scale-200.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ApplicationDefinition Include=\"App.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </ApplicationDefinition>\n    <Page Include=\"MainPage.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NETCore.UniversalWindowsPlatform\">\n      <Version>6.1.7</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Flutter.Sample.App\\Flutter.Sample.App.csproj\">\n      <Project>{e0fb1bf8-e32c-4a8a-9ae6-e501cc68f279}</Project>\n      <Name>Flutter.Sample.App</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\Flutter.Shell.UWP\\Flutter.Shell.UWP.csproj\">\n      <Project>{a5bf7067-2a28-4002-aeb4-1965d0dedc14}</Project>\n      <Name>Flutter.Shell.UWP</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' \">\n    <VisualStudioVersion>14.0</VisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "Flutter.Sample.UWP/MainPage.xaml",
    "content": "﻿<fluttershell:FlutterPage\n    x:Class=\"Flutter.Sample.UWP.MainPage\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n    xmlns:fluttershell=\"using:Flutter.Shell.UWP\"\n    mc:Ignorable=\"d\"\n    Background=\"{ThemeResource ApplicationPageBackgroundThemeBrush}\" />\n"
  },
  {
    "path": "Flutter.Sample.UWP/MainPage.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices.WindowsRuntime;\nusing Windows.Foundation;\nusing Windows.Foundation.Collections;\nusing Windows.UI.Xaml;\nusing Windows.UI.Xaml.Controls;\nusing Windows.UI.Xaml.Controls.Primitives;\nusing Windows.UI.Xaml.Data;\nusing Windows.UI.Xaml.Input;\nusing Windows.UI.Xaml.Media;\nusing Windows.UI.Xaml.Navigation;\n\n// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409\n\nnamespace Flutter.Sample.UWP\n{\n    /// <summary>\n    /// An empty page that can be used on its own or navigated to within a Frame.\n    /// </summary>\n    public sealed partial class MainPage\n    {\n        public MainPage()\n        {\n            this.InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "Flutter.Sample.UWP/Package.appxmanifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<Package\n  xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\"\n  xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n  xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\"\n  IgnorableNamespaces=\"uap mp\">\n\n  <Identity\n    Name=\"68e2ed5a-6b47-4c9b-9fe0-bd7501495a01\"\n    Publisher=\"CN=Adam\"\n    Version=\"1.0.0.0\" />\n\n  <mp:PhoneIdentity PhoneProductId=\"68e2ed5a-6b47-4c9b-9fe0-bd7501495a01\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n\n  <Properties>\n    <DisplayName>Flutter.Sample.UWP</DisplayName>\n    <PublisherDisplayName>Adam</PublisherDisplayName>\n    <Logo>Assets\\StoreLogo.png</Logo>\n  </Properties>\n\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n  </Dependencies>\n\n  <Resources>\n    <Resource Language=\"x-generate\"/>\n  </Resources>\n\n  <Applications>\n    <Application Id=\"App\"\n      Executable=\"$targetnametoken$.exe\"\n      EntryPoint=\"Flutter.Sample.UWP.App\">\n      <uap:VisualElements\n        DisplayName=\"Flutter.Sample.UWP\"\n        Square150x150Logo=\"Assets\\Square150x150Logo.png\"\n        Square44x44Logo=\"Assets\\Square44x44Logo.png\"\n        Description=\"Flutter.Sample.UWP\"\n        BackgroundColor=\"transparent\">\n        <uap:DefaultTile Wide310x150Logo=\"Assets\\Wide310x150Logo.png\"/>\n        <uap:SplashScreen Image=\"Assets\\SplashScreen.png\" />\n      </uap:VisualElements>\n    </Application>\n  </Applications>\n\n  <Capabilities>\n    <Capability Name=\"internetClient\" />\n  </Capabilities>\n</Package>"
  },
  {
    "path": "Flutter.Sample.UWP/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Flutter.Sample.UWP\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Flutter.Sample.UWP\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "Flutter.Sample.UWP/Properties/Default.rd.xml",
    "content": "<!--\n    This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most\n    developers. However, you can modify these parameters to modify the behavior of the .NET Native\n    optimizer.\n\n    Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919\n\n    To fully enable reflection for App1.MyClass and all of its public/private members\n    <Type Name=\"App1.MyClass\" Dynamic=\"Required All\"/>\n\n    To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32\n    <TypeInstantiation Name=\"App1.AppClass\" Arguments=\"System.Int32\" Activate=\"Required Public\" />\n\n    Using the Namespace directive to apply reflection policy to all the types in a particular namespace\n    <Namespace Name=\"DataClasses.ViewModels\" Serialize=\"All\" />\n-->\n\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Application>\n    <!--\n      An Assembly element with Name=\"*Application*\" applies to all assemblies in\n      the application package. The asterisks are not wildcards.\n    -->\n    <Assembly Name=\"*Application*\" Dynamic=\"Required All\" />\n    \n    \n    <!-- Add your application specific runtime directives here. -->\n\n\n  </Application>\n</Directives>"
  },
  {
    "path": "Flutter.Shell.Droid/Flutter.Shell.Droid.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProductVersion>8.0.30703</ProductVersion>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectGuid>{C9E1CAA4-53F3-4032-92A0-81F5322D446B}</ProjectGuid>\n    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <TemplateGuid>{9ef11e43-1701-4396-8835-8392d57abb70}</TemplateGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Flutter.Shell.Droid</RootNamespace>\n    <AssemblyName>Flutter.Shell.Droid</AssemblyName>\n    <FileAlignment>512</FileAlignment>\n    <AndroidResgenFile>Resources\\Resource.Designer.cs</AndroidResgenFile>\n    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>\n    <AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>\n    <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>portable</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"Mono.Android\" />\n    <Reference Include=\"mscorlib\" />\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Resources\\Resource.Designer.cs\" />\n    <Compile Include=\"FlutterCanvas.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Xamarin.Android.Support.v7.AppCompat\" Version=\"27.0.2.1\" />\n    <PackageReference Include=\"SkiaSharp\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n    <PackageReference Include=\"SkiaSharp.Views\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <AndroidResource Include=\"Resources\\values\\strings.xml\" />\n    <AndroidResource Include=\"Resources\\layout\\FlutterPage.axml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Folder Include=\"Resources\\drawable\\\" />\n    <Folder Include=\"Resources\\layout\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\FlutterBinding\\FlutterBinding.csproj\">\n      <Project>{c9313643-3357-4872-9b00-03e2c79ad297}</Project>\n      <Name>FlutterBinding</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\FlutterSDK\\FlutterSDK.csproj\">\n      <Project>{0781218d-0bcf-4528-aa32-a1937572e43b}</Project>\n      <Name>FlutterSDK</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Xamarin\\Android\\Xamarin.Android.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "Flutter.Shell.Droid/FlutterCanvas.cs",
    "content": "﻿using Android.OS;\nusing Android.Support.V7.App;\nusing FlutterBinding.UI;\nusing SkiaSharp.Views.Android;\n\nnamespace Flutter.Shell.Droid\n{\n    public class FlutterCanvas : AppCompatActivity\n    {\n        public SKCanvasView Canvas { get; private set; }\n        public FlutterSurface Surface { get; private set; }\n\n        protected override void OnCreate(Bundle savedInstanceState)\n        {\n            base.OnCreate(savedInstanceState);\n            SetContentView(Resource.Layout.FlutterPage);\n\n            Canvas = FindViewById<SKCanvasView>(Resource.Id.skiaView);\n\n            var scale = Resources.DisplayMetrics.Density;\n\n            if (Canvas != null)\n            {\n                Surface = new FlutterSurface(scale);\n            }\n\n            Canvas.PaintSurface += OnCanvasPaintSurface;\n        }\n\n        private void OnCanvasPaintSurface(object sender, SKPaintSurfaceEventArgs args)\n        {\n            Surface.OnPaintSurface(args.Surface, args.Info);\n        }\n\n        protected override void OnDestroy()\n        {\n            Canvas.PaintSurface -= OnCanvasPaintSurface;\n            base.OnDestroy();\n        }\n    }\n}"
  },
  {
    "path": "Flutter.Shell.Droid/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Android.App;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Flutter.Shell.Droid\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Flutter.Shell.Droid\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: ComVisible(false)]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "Flutter.Shell.Droid/Resources/layout/FlutterPage.axml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <skiasharp.views.android.SKCanvasView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:id=\"@+id/skiaView\" />\n</FrameLayout>\n"
  },
  {
    "path": "Flutter.Shell.Droid/Resources/values/Strings.xml",
    "content": "<resources>\n    <string name=\"hello\">Hello World, Click Me!</string>\n    <string name=\"app_name\">Flutter.Shell.Droid</string>\n</resources>\n"
  },
  {
    "path": "Flutter.Shell.UWP/Flutter.Shell.UWP.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Flutter.Shell.UWP</RootNamespace>\n    <AssemblyName>Flutter.Shell.UWP</AssemblyName>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>\n    <TargetPlatformVersion Condition=\" '$(TargetPlatformVersion)' == '' \">10.0.17763.0</TargetPlatformVersion>\n    <TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>\n    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <PlatformTarget>x86</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <PlatformTarget>x86</PlatformTarget>\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\n    <PlatformTarget>ARM</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\n    <PlatformTarget>ARM</PlatformTarget>\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <PlatformTarget>x64</PlatformTarget>\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup>\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"FlutterCanvas.cs\" />\n    <Compile Include=\"FlutterPage.xaml.cs\">\n      <DependentUpon>FlutterPage.xaml</DependentUpon>\n    </Compile>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <EmbeddedResource Include=\"Properties\\Flutter.Shell.UWP.rd.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NETCore.UniversalWindowsPlatform\">\n      <Version>6.1.7</Version>\n    </PackageReference>\n    <PackageReference Include=\"SkiaSharp\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n    <PackageReference Include=\"SkiaSharp.Views\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\FlutterBinding\\FlutterBinding.csproj\">\n      <Project>{c9313643-3357-4872-9b00-03e2c79ad297}</Project>\n      <Name>FlutterBinding</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\FlutterSDK\\FlutterSDK.csproj\">\n      <Project>{0781218d-0bcf-4528-aa32-a1937572e43b}</Project>\n      <Name>FlutterSDK</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <Page Include=\"FlutterPage.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Include=\"Themes\\Generic.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"VisualStudioToolsManifest.xml\" />\n  </ItemGroup>\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' \">\n    <VisualStudioVersion>14.0</VisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "Flutter.Shell.UWP/FlutterCanvas.cs",
    "content": "﻿using System;\nusing Windows.Graphics.Display;\nusing Windows.UI.Xaml;\nusing Windows.UI.Xaml.Controls;\nusing FlutterBinding.UI;\nusing SkiaSharp.Views.UWP;\n\nnamespace Flutter.Shell.UWP\n{\n    //[TemplatePart(Name = \"Content\")]\n    public sealed class FlutterCanvas : ContentControl\n    {\n        private const string       CanvasKey = \"Canvas\";\n\n        public SKXamlCanvas Canvas { get; private set; }\n        public FlutterSurface Surface { get; private set; }\n\n        public FlutterCanvas()\n        {\n            DefaultStyleKey = typeof(FlutterCanvas);\n        }\n\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        /// <inheritdoc />\n        protected override void OnApplyTemplate()\n        {\n            if (Canvas != null)\n                Canvas.PaintSurface -= OnCanvasOnPaintSurface;\n\n            Canvas = GetTemplateChild(CanvasKey) as SKXamlCanvas;\n            if (Canvas == null)\n                return;\n\n            var display = DisplayInformation.GetForCurrentView();\n            var scale   = display.LogicalDpi / 96.0f;\n\n            Surface = new FlutterSurface(scale);\n            Canvas.PaintSurface += OnCanvasOnPaintSurface;\n\n            base.OnApplyTemplate();\n        }\n\n        private void OnCanvasOnPaintSurface(object s, SKPaintSurfaceEventArgs args)\n        {\n            Surface.OnPaintSurface(args.Surface, args.Info);\n        }\n\n        /// <inheritdoc />\n        protected override void OnContentChanged(object oldContent, object newContent)\n        {\n            if (oldContent is FrameworkElement oldElement)\n                oldElement.SizeChanged -= OnSizeChanged;\n\n            if (newContent is FrameworkElement newElement)\n                newElement.SizeChanged += OnSizeChanged;\n\n            base.OnContentChanged(oldContent, newContent);\n        }\n\n        private void OnSizeChanged(object sender, SizeChangedEventArgs e)\n        {\n            // TODO: Notify\n        }\n    }\n}\n"
  },
  {
    "path": "Flutter.Shell.UWP/FlutterPage.xaml",
    "content": "﻿<Page\n    x:Class=\"Flutter.Shell.UWP.FlutterPage\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:Flutter.Shell.UWP\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n    mc:Ignorable=\"d\" \n    Background=\"{ThemeResource ApplicationPageBackgroundThemeBrush}\">\n\n    <local:FlutterCanvas x:Name=\"FlutterCanvas\" x:FieldModifier=\"public\" />\n\n</Page>\n"
  },
  {
    "path": "Flutter.Shell.UWP/FlutterPage.xaml.cs",
    "content": "﻿using Windows.ApplicationModel.Core;\nusing Windows.UI;\nusing Windows.UI.ViewManagement;\nusing Windows.UI.Xaml;\n\nnamespace Flutter.Shell.UWP\n{\n    /// <summary>\n    /// Flutter Page\n    /// </summary>\n    public partial class FlutterPage\n    {\n        public FlutterPage()\n        {\n            InitializeComponent();\n            HideTitleBar();\n        }\n\n        private static void HideTitleBar()\n        {\n            var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;\n            coreTitleBar.ExtendViewIntoTitleBar = true;\n\n            var titleBar = ApplicationView.GetForCurrentView().TitleBar;\n            titleBar.ForegroundColor         = Colors.White;\n            titleBar.BackgroundColor         = Colors.Transparent;\n            titleBar.ButtonForegroundColor   = Colors.White;\n            titleBar.ButtonBackgroundColor   = Colors.Transparent;\n            titleBar.InactiveBackgroundColor = Colors.Transparent;\n        }\n    }\n}\n"
  },
  {
    "path": "Flutter.Shell.UWP/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Flutter.Shell.UWP\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Flutter.Shell.UWP\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "Flutter.Shell.UWP/Properties/Flutter.Shell.UWP.rd.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    This file contains Runtime Directives, specifications about types your application accesses\n    through reflection and other dynamic code patterns. Runtime Directives are used to control the\n    .NET Native optimizer and ensure that it does not remove code accessed by your library. If your\n    library does not do any reflection, then you generally do not need to edit this file. However,\n    if your library reflects over types, especially types passed to it or derived from its types,\n    then you should write Runtime Directives.\n\n    The most common use of reflection in libraries is to discover information about types passed\n    to the library. Runtime Directives have three ways to express requirements on types passed to\n    your library.\n\n    1.  Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter\n        Use these directives to reflect over types passed as a parameter.\n\n    2.  SubTypes\n        Use a SubTypes directive to reflect over types derived from another type.\n\n    3.  AttributeImplies\n        Use an AttributeImplies directive to indicate that your library needs to reflect over\n        types or methods decorated with an attribute.\n\n    For more information on writing Runtime Directives for libraries, please visit\n    https://go.microsoft.com/fwlink/?LinkID=391919\n-->\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Library Name=\"Flutter.Shell.UWP\">\n\n  \t<!-- add directives for your library here -->\n\n  </Library>\n</Directives>\n"
  },
  {
    "path": "Flutter.Shell.UWP/Themes/Generic.xaml",
    "content": "<ResourceDictionary\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" \n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:Flutter.Shell.UWP\"\n    xmlns:skia=\"using:SkiaSharp.Views.UWP\">\n    \n    <Color x:Key=\"CanvasColor\">#0091ea</Color>\n    \n    <SolidColorBrush x:Key=\"CanvasBrush\" Color=\"{StaticResource CanvasColor}\" />\n\n    <Style TargetType=\"local:FlutterCanvas\" >\n        <Setter Property=\"Background\" Value=\"{StaticResource CanvasBrush}\" />\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"local:FlutterCanvas\">\n                    <Grid\n                        Background=\"{TemplateBinding Background}\"\n                        BorderBrush=\"{TemplateBinding BorderBrush}\"\n                        BorderThickness=\"{TemplateBinding BorderThickness}\"\n                        Margin=\"{TemplateBinding Margin}\"\n                        Padding=\"{TemplateBinding Padding}\">\n\n                        <skia:SKXamlCanvas x:Name=\"Canvas\" />\n                        <ContentPresenter />\n\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>\n"
  },
  {
    "path": "Flutter.Shell.UWP/VisualStudioToolsManifest.xml",
    "content": "﻿<FileList>\n  <File Reference=\"Flutter.Shell.UWP.dll\">\n    <ToolboxItems VSCategory=\"Flutter Shell Tookit\" BlendCategory=\"Flutter Shell Toolkit\">\n      <Item Type=\"Flutter.Shell.UWP\" />\n    </ToolboxItems>\n  </File>\n</FileList>"
  },
  {
    "path": "FlutterBinding/Engine/Compositing/NativeScene.cs",
    "content": "﻿using FlutterBinding.Flow.Layers;\nusing FlutterBinding.UI;\nusing SkiaSharp;\n\nnamespace FlutterBinding.Engine.Compositing\n{\n    public class NativeScene\n    {\n\n        public static NativeScene Create(Layer rootLayer,\n                                 uint rasterizerTracingThreshold,\n                                 bool checkerboardRasterCacheImages,\n                                 bool checkerboardOffscreenLayers)\n        {\n            return new NativeScene(\n                rootLayer, rasterizerTracingThreshold,\n                checkerboardRasterCacheImages, checkerboardOffscreenLayers);\n        }\n\n        LayerTree m_layerTree;\n\n\n        public LayerTree TakeLayerTree()\n        {\n            return m_layerTree;\n        }\n\n        public NativeScene(Layer rootLayer,\n             uint rasterizerTracingThreshold,\n             bool checkerboardRasterCacheImages,\n             bool checkerboardOffscreenLayers)\n        {\n            m_layerTree = new LayerTree();\n            m_layerTree.set_root_layer(rootLayer);\n            m_layerTree.set_rasterizer_tracing_threshold(rasterizerTracingThreshold);\n            m_layerTree.set_checkerboard_raster_cache_images(\n                checkerboardRasterCacheImages);\n            m_layerTree.set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);\n        }\n\n        public string ToImage(int width,\n                              int height,\n                              _Callback<SKImage> raw_image_callback)\n        {\n\n            if (raw_image_callback == null)\n            {\n                return \"Image callback was invalid\";\n            }\n\n            if (m_layerTree == null)\n            {\n                return \"Scene did not contain a layer tree.\";\n            }\n\n            if (width == 0 || height == 0)\n            {\n                return \"Image dimensions for scene were invalid.\";\n            }\n\n            // We can't create an image on this task runner because we don't have a\n            // graphics context. Even if we did, it would be slow anyway. Also, this\n            // thread owns the sole reference to the layer tree. So we flatten the layer\n            // tree into a picture and use that as the thread transport mechanism.\n\n            var picture_bounds = new SKSizeI(width, height);\n            var picture = m_layerTree.Flatten(new SKRect(0, 0, width, height));\n\n            if (picture == null)\n            {\n                // Already in Dart scope.\n                return \"Could not flatten scene into a layer tree.\";\n            }\n\n            // TODO: Call Callback to create actual image.\n           \n            return string.Empty;\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Compositing/NativeSceneBuilder.cs",
    "content": "﻿using FlutterBinding.Engine.Painting;\nusing FlutterBinding.Flow.Layers;\nusing FlutterBinding.UI;\nusing SkiaSharp;\nusing System.Collections.Generic;\n\nnamespace FlutterBinding.Engine.Compositing\n{\n    //https://github.com/flutter/engine/blob/master/lib/ui/compositing/scene_builder.h\n    //https://github.com/flutter/engine/blob/master/lib/ui/compositing/scene_builder.cc\n\n    public class NativeSceneBuilder\n    {\n        ContainerLayer root_layer_;\n        ContainerLayer current_layer_;\n\n        protected void Constructor() { }\n\n        protected void PushTransform(List<double> matrix4)\n        {\n            var sk_matrix = Matrix.ToSkMatrix(matrix4);\n            var layer = new TransformLayer();\n            layer.set_transform(sk_matrix);\n            PushLayer(layer);\n        }\n\n        protected NativeEngineLayer PushOffset(double dx, double dy)\n        {\n            SKMatrix sk_matrix = SKMatrix.MakeTranslation((float)dx, (float)dy);\n            var layer = new TransformLayer();\n            layer.set_transform(sk_matrix);\n            PushLayer(layer);\n            return NativeEngineLayer.MakeRetained(layer);\n        }\n\n        protected void PushClipRect(double left,\n                                double right,\n                                double top,\n                                double bottom,\n                                int clipBehavior)\n        {\n            var clipRect = new SKRect((float)left, (float)top, (float)right, (float)bottom);\n            var layer = new ClipRectLayer((Flow.Layers.Clip)clipBehavior);\n            layer.set_clip_rect(clipRect);\n            PushLayer(layer);\n        }\n\n        protected void PushClipPath(SKPath path, int clipBehavior)\n        {\n            // FML_DCHECK(clip_behavior != flow::Clip::none);\n            var layer = new ClipPathLayer((Flow.Layers.Clip)clipBehavior);\n            layer.set_clip_path(path);\n            PushLayer(layer);\n        }\n\n        protected void PushLayer(ContainerLayer layer)\n        {\n            if (root_layer_ == null)\n            {\n                root_layer_ = layer;\n                current_layer_ = root_layer_;\n                return;\n            }\n\n            if (current_layer_ == null)\n            {\n                return;\n            }\n\n            ContainerLayer newLayer = layer;\n            current_layer_.Add(layer);\n            current_layer_ = newLayer;\n        }\n        //Flow.SkiaUnrefQueue _queue = new Flow.SkiaUnrefQueue();\n        public void AddPicture(double dx, double dy, SKPicture picture, int hints)\n        {\n            if (current_layer_ == null)\n            {\n                return;\n            }\n            SKPoint offset = new SKPoint((float)dx, (float)dy);\n            SKRect pictureRect = picture.CullRect;\n            pictureRect.Offset(offset.X, offset.Y);\n            var layer = new PictureLayer();\n            layer.set_offset(offset);\n            layer.set_picture(picture);\n            layer.set_is_complex((hints & 1) == 1);\n            layer.set_will_change((hints & 2) == 2);\n            current_layer_.Add(layer);\n        }\n\n        public void Pop()\n        {\n            if (current_layer_ == null)\n            {\n                return;\n            }\n            current_layer_ = current_layer_.parent();\n        }\n        uint rasterizer_tracing_threshold_ = 0;\n        bool checkerboard_raster_cache_images_ = false;\n        bool checkerboard_offscreen_layers_ = false;\n\n        public Scene Build()\n        {\n            var scene = new Scene(root_layer_, rasterizer_tracing_threshold_,\n     checkerboard_raster_cache_images_, checkerboard_offscreen_layers_);\n            \n            return scene;\n        }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Engine.cs",
    "content": "﻿using FlutterBinding.Flow.Layers;\nusing SkiaSharp;\n\nnamespace FlutterBinding.Engine\n{\n    public class Engine\n    {\n        Engine() { }\n        static Engine _instance;\n        public static Engine Instance => _instance ?? (_instance = new Engine());\n\n        SKCanvas _canvas;\n        public void LoadCanvas(SKCanvas canvas)\n        {\n            _canvas = canvas;\n        }\n\n        double _physicalWidth;\n        double _physicalHeight;\n        public void SetSize(double physicalWidth, double physicalHeight)\n        {\n            _physicalWidth = physicalWidth;\n            _physicalHeight = physicalHeight;\n        }\n\n        public void Render(LayerTree layer_tree)\n        {\n            if (layer_tree == null)\n                return;\n\n            SKSizeI frame_size = new SKSizeI((int)_physicalWidth,\n                                             (int)_physicalHeight);\n            if (frame_size.IsEmpty)\n                return;\n\n            layer_tree.set_frame_size(frame_size);\n\n            var picture = layer_tree.Flatten(new SKRect(0, 0, frame_size.Width, frame_size.Height));\n          \n            _canvas.DrawPicture(picture);\n\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/Matrix.cs",
    "content": "﻿using SkiaSharp;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public class Matrix\n    {\n        // Mappings from SkMatrix-index to input-index.\n        static int[] kSkMatrixIndexToMatrix4Index = new int[] {\n                                                                    // clang-format off\n                                                                    0, 4, 12,\n                                                                    1, 5, 13,\n                                                                    3, 7, 15,\n                                                                    // clang-format on\n                                                                };\n\n        public static SKMatrix ToSkMatrix(List<float> matrix4)\n        {\n            return ToSkMatrix(matrix4.Cast<double>().ToList());\n        }\n\n        public static SKMatrix ToSkMatrix(List<double> matrix4)\n        {\n            SKMatrix sk_matrix = new SKMatrix();\n            for (int i = 0; i < 9; ++i)\n            {\n                int matrix4_index = kSkMatrixIndexToMatrix4Index[i];\n                if (matrix4_index < matrix4.Count)\n                    sk_matrix.Values[i] = (float)matrix4[matrix4_index];\n                else\n                    sk_matrix.Values[i] = 0.0f;\n            }\n            return sk_matrix;\n        }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativeCanvas.cs",
    "content": "﻿using SkiaSharp;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public class NativeCanvas : SKCanvas\n    {\n        public NativeCanvas(SKBitmap bitmap) : base(bitmap) { }\n\n        public SKCanvas RecordingCanvas { get; set; }\n\n        public void Constructor(SKPictureRecorder recorder,\n                          double left,\n                          double top,\n                          double right,\n                          double bottom)\n        {\n            var canvas = recorder.BeginRecording(new SKRect((float)left, (float)top, (float)right, (float)bottom));\n            RecordingCanvas = canvas;\n        }\n\n\n    }\n}"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativeCodec.cs",
    "content": "﻿using FlutterBinding.UI;\nusing SkiaSharp;\nusing System.Collections.Generic;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public static class NativeCodec\n    {\n        public static string InstantiateImageCodec(List<int> list, _Callback<SKCodec> callback, _ImageInfo imageInfo, double decodedCacheRatioCap)\n        {           \n            return null;\n        }\n\n        public static SKImage GetImage(this SKCodecFrameInfo info, SKCodec codec)\n        {\n            return SKImage.Create(codec.Info);\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativeEngineLayer.cs",
    "content": "﻿using FlutterBinding.Flow.Layers;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    //https://github.com/flutter/engine/blob/master/lib/ui/painting/engine_layer.h\n    //https://github.com/flutter/engine/blob/master/lib/ui/painting/engine_layer.cc\n       \n    public class NativeEngineLayer\n    {\n\n        public static NativeEngineLayer MakeRetained(ContainerLayer layer)\n        {\n            return new NativeEngineLayer(layer);\n        }\n        \n        ContainerLayer _layer;\n        NativeEngineLayer(ContainerLayer layer)\n        {\n            _layer = layer;\n        }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativePath.cs",
    "content": "﻿using SkiaSharp;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public class NativePath: SKPath\n    {\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativePathMetric.cs",
    "content": "﻿using SkiaSharp;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public class NativePathMetric: SKPathMeasure\n    {\n        public NativePathMetric(SKPath path, bool forceClosed = false, float resScale = 1) : base(path, forceClosed, resScale)\n        { }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativePicture.cs",
    "content": "﻿using SkiaSharp;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    //public class NativePicture: SKPicture\n    //{\n    //}\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Painting/NativePictureRecorder.cs",
    "content": "﻿using SkiaSharp;\n\nnamespace FlutterBinding.Engine.Painting\n{\n    public class NativePictureRecorder: SKPictureRecorder\n    {\n\n        protected SKCanvas Canvas;\n        public void SetCanvas(SKCanvas canvas)\n            => this.Canvas = canvas;\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Text/NativeParagraph.cs",
    "content": "﻿using FlutterBinding.Engine.Painting;\nusing SkiaSharp;\n\nnamespace FlutterBinding.Engine.Text\n{\n    public class NativeParagraph\n    {\n        public string Text { get; set; }\n\n        // Temporary, to use for all text, until SkiaSharp can be updated\n        SKPaint _paint = new SKPaint\n        {\n            Color = SKColors.Black,\n            IsAntialias = true,\n            Style = SKPaintStyle.Fill,\n            TextAlign = SKTextAlign.Center,\n            TextSize = 24\n        };\n\n        public void Paint(SKCanvas canvas, double x, double y)\n        {           \n            canvas.DrawText(this.Text, (float)x, (float)y, _paint);            \n        }\n\n        double _width;\n        public void Layout(double width)\n        {\n            _width = width;\n        }\n\n        public float Width => _paint.MeasureText(Text);\n        public float Height => 24;\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Text/NativeParagraphBuilder.cs",
    "content": "﻿using FlutterBinding.UI;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Engine.Text\n{\n    // https://github.com/flutter/engine/blob/master/lib/ui/text/paragraph_builder.h\n    // https://github.com/flutter/engine/blob/master/lib/ui/text/paragraph_builder.cc\n\n    public class NativeParagraphBuilder\n    {\n\n        // TextStyle\n\n\n\n        const int tsColorIndex = 1;\n\n        const int tsTextDecorationIndex = 2;\n\n        const int tsTextDecorationColorIndex = 3;\n\n        const int tsTextDecorationStyleIndex = 4;\n\n        const int tsFontWeightIndex = 5;\n\n        const int tsFontStyleIndex = 6;\n\n        const int tsTextBaselineIndex = 7;\n\n        const int tsFontFamilyIndex = 8;\n\n        const int tsFontSizeIndex = 9;\n\n        const int tsLetterSpacingIndex = 10;\n\n        const int tsWordSpacingIndex = 11;\n\n        const int tsHeightIndex = 12;\n\n        const int tsLocaleIndex = 13;\n\n        const int tsBackgroundIndex = 14;\n\n        const int tsForegroundIndex = 15;\n\n        const int tsTextShadowsIndex = 16;\n\n\n\n        const int tsColorMask = 1 << tsColorIndex;\n\n        const int tsTextDecorationMask = 1 << tsTextDecorationIndex;\n\n        const int tsTextDecorationColorMask = 1 << tsTextDecorationColorIndex;\n\n        const int tsTextDecorationStyleMask = 1 << tsTextDecorationStyleIndex;\n\n        const int tsFontWeightMask = 1 << tsFontWeightIndex;\n\n        const int tsFontStyleMask = 1 << tsFontStyleIndex;\n\n        const int tsTextBaselineMask = 1 << tsTextBaselineIndex;\n\n        const int tsFontFamilyMask = 1 << tsFontFamilyIndex;\n\n        const int tsFontSizeMask = 1 << tsFontSizeIndex;\n\n        const int tsLetterSpacingMask = 1 << tsLetterSpacingIndex;\n\n        const int tsWordSpacingMask = 1 << tsWordSpacingIndex;\n\n        const int tsHeightMask = 1 << tsHeightIndex;\n\n        const int tsLocaleMask = 1 << tsLocaleIndex;\n\n        const int tsBackgroundMask = 1 << tsBackgroundIndex;\n\n        const int tsForegroundMask = 1 << tsForegroundIndex;\n\n        const int tsTextShadowsMask = 1 << tsTextShadowsIndex;\n\n\n\n        // ParagraphStyle\n\n\n\n        const int psTextAlignIndex = 1;\n\n        const int psTextDirectionIndex = 2;\n\n        const int psFontWeightIndex = 3;\n\n        const int psFontStyleIndex = 4;\n\n        const int psMaxLinesIndex = 5;\n\n        const int psFontFamilyIndex = 6;\n\n        const int psFontSizeIndex = 7;\n\n        const int psLineHeightIndex = 8;\n\n        const int psEllipsisIndex = 9;\n\n        const int psLocaleIndex = 10;\n\n\n\n        const int psTextAlignMask = 1 << psTextAlignIndex;\n\n        const int psTextDirectionMask = 1 << psTextDirectionIndex;\n\n        const int psFontWeightMask = 1 << psFontWeightIndex;\n\n        const int psFontStyleMask = 1 << psFontStyleIndex;\n\n        const int psMaxLinesMask = 1 << psMaxLinesIndex;\n\n        const int psFontFamilyMask = 1 << psFontFamilyIndex;\n\n        const int psFontSizeMask = 1 << psFontSizeIndex;\n\n        const int psLineHeightMask = 1 << psLineHeightIndex;\n\n        const int psEllipsisMask = 1 << psEllipsisIndex;\n\n        const int psLocaleMask = 1 << psLocaleIndex;\n\n\n\n        // TextShadows decoding\n\n        const uint kColorDefault = 0xFF000000;\n\n        const uint kBytesPerShadow = 16;\n\n        const uint kShadowPropertiesCount = 4;\n\n        const uint kColorOffset = 0;\n\n        const uint kXOffset = 1;\n\n        const uint kYOffset = 2;\n\n        const uint kBlurOffset = 3;\n\n        //Txt.ParagraphBuilder m_paragraphBuilder;\n\n        protected NativeParagraphBuilder(List<int> encoded,\n                         string fontFamily,\n                         double fontSize,\n                         double lineHeight,\n                         string ellipsis,\n                         string locale)\n        {\n\n            //int mask = encoded[0];\n\n            //Txt.ParagraphStyle style;\n\n            //if (mask & psTextAlignMask)\n\n            //    style.text_align = TextAlign(encoded[psTextAlignIndex]);\n\n\n\n            //if (mask & psTextDirectionMask)\n\n            //    style.text_direction = txt::TextDirection(encoded[psTextDirectionIndex]);\n\n\n\n            //if (mask & psFontWeightMask)\n\n            //    style.font_weight =\n\n            //        static_cast<txt::FontWeight>(encoded[psFontWeightIndex]);\n\n\n\n            //if (mask & psFontStyleMask)\n\n            //    style.font_style = static_cast<txt::FontStyle>(encoded[psFontStyleIndex]);\n\n\n\n            //if (mask & psFontFamilyMask)\n\n            //    style.font_family = fontFamily;\n\n\n\n            //if (mask & psFontSizeMask)\n\n            //    style.font_size = fontSize;\n\n\n\n            //if (mask & psLineHeightMask)\n\n            //    style.line_height = lineHeight;\n\n\n\n            //if (mask & psMaxLinesMask)\n\n            //    style.max_lines = encoded[psMaxLinesIndex];\n\n\n\n            //if (mask & psEllipsisMask)\n\n            //    style.ellipsis = ellipsis;\n\n\n\n            //if (mask & psLocaleMask)\n\n            //    style.locale = locale;\n\n\n\n            //Txt.FontCollection font_collection =\n\n            //    UIDartState::Current()->window()->client()->GetFontCollection();\n\n            //m_paragraphBuilder = new Txt.ParagraphBuilder(\n            //    style, font_collection.GetFontCollection());\n\n        }  // namespace blink\n\n\n        string _text = \"\";\n        protected string AddText(string text)\n        {\n            if (string.IsNullOrEmpty(text))\n                return null;\n\n            _text += text;\n            \n            // TODO:\n            //m_paragraphBuilder->AddText(text);\n\n            return null;\n        }\n\n        public Paragraph Build()\n        {\n            return new Paragraph() { Text = _text };\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Text/NativeParagraphStyle.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Engine.Text\n{\n    public class NativeParagraphStyle\n    {\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Engine/Window/NativeWindow.cs",
    "content": "﻿using FlutterBinding.UI;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Engine.Window\n{\n    public class NativeWindow\n    {\n\n        public void Render(Scene scene)\n        {\n            Engine.Instance.Render(scene.TakeLayerTree());\n        }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Flow/CompositorContext.cs",
    "content": "﻿using FlutterBinding.Flow.Layers;\nusing SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow\n{\n    public class CompositorContext\n    {\n        public class ScopedFrame : System.IDisposable\n        {\n            public ScopedFrame(CompositorContext context, GRContext gr_context, SKCanvas canvas, ExternalViewEmbedder view_embedder, SKMatrix root_surface_transformation, bool instrumentation_enabled)\n            {\n                this.context_ = context;\n                this.gr_context_ = gr_context;\n                this.canvas_ = canvas;\n                this.view_embedder_ = view_embedder;\n                this.root_surface_transformation_ = root_surface_transformation;\n                this.instrumentation_enabled_ = instrumentation_enabled;\n                context_.BeginFrame(this, instrumentation_enabled_);\n            }\n\n            public virtual void Dispose()\n            {\n                context_.EndFrame(this, instrumentation_enabled_);\n            }\n\n            public SKCanvas canvas()\n            {\n                return canvas_;\n            }\n\n            public ExternalViewEmbedder view_embedder()\n            {\n                return view_embedder_;\n            }\n\n            public CompositorContext context()\n            {\n                return context_;\n            }\n\n            public SKMatrix root_surface_transformation()\n            {\n                return root_surface_transformation_;\n            }\n\n            public GRContext gr_context()\n            {\n                return gr_context_;\n            }\n\n            public virtual bool Raster(LayerTree layer_tree, bool ignore_raster_cache)\n            {\n                layer_tree.Preroll(this, ignore_raster_cache);\n                layer_tree.Paint(this, ignore_raster_cache);\n                return true;\n            }\n\n            private CompositorContext context_;\n            private GRContext gr_context_;\n            private SKCanvas canvas_;\n            private ExternalViewEmbedder view_embedder_;\n            private readonly SKMatrix root_surface_transformation_;\n            private readonly bool instrumentation_enabled_;\n        }\n\n        public virtual ScopedFrame AcquireFrame(GRContext gr_context, SKCanvas canvas, ExternalViewEmbedder view_embedder, SKMatrix root_surface_transformation, bool instrumentation_enabled)\n        {\n            return new ScopedFrame(this, gr_context, canvas, view_embedder, root_surface_transformation, instrumentation_enabled);\n        }\n\n        public void OnGRContextCreated()\n        {\n            texture_registry_.OnGRContextCreated();\n            raster_cache_.Clear();\n        }\n\n        public void OnGRContextDestroyed()\n        {\n            texture_registry_.OnGRContextDestroyed();\n            raster_cache_.Clear();\n        }\n\n        public RasterCache raster_cache()\n        {\n            return raster_cache_;\n        }\n\n        public TextureRegistry texture_registry()\n        {\n            return texture_registry_;\n        }\n\n        private RasterCache raster_cache_ = new RasterCache();\n        private TextureRegistry texture_registry_ = new TextureRegistry();\n\n        private void BeginFrame(ScopedFrame frame, bool enable_instrumentation)\n        {\n        }\n\n        private void EndFrame(ScopedFrame frame, bool enable_instrumentation)\n        {\n            raster_cache_.SweepAfterFrame();\n        }\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/EmbeddedViews.cs",
    "content": "﻿using static FlutterBinding.Flow.Helper;\nusing SkiaSharp;\n\n// Copyright 2017 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\nnamespace FlutterBinding.Flow\n{\n\n    public class EmbeddedViewParams\n    {\n        public SKPoint offsetPixels = new SKPoint();\n        public SKSize sizePoints = new SKSize();\n    }\n\n    // This is only used on iOS when running in a non headless mode,\n    // in this case ViewEmbedded is a reference to the\n    // FlutterPlatformViewsController which is owned by FlutterViewController.\n    public class ExternalViewEmbedder\n    {      \n\n        // Must be called on the UI thread.\n        public virtual void CompositeEmbeddedView(ulong view_id, EmbeddedViewParams @params)\n        {\n        }\n    }\n\n} // namespace flow\n\n"
  },
  {
    "path": "FlutterBinding/Flow/GlobalMembers.cs",
    "content": "﻿using SkiaSharp;\nusing System;\nusing static FlutterBinding.Flow.Helper;\n\nnamespace FlutterBinding.Flow\n{\n    public static class GlobalMembers\n    {\n        public static readonly int kDisplayRasterizerStatistics = 1 << 0;\n        public static readonly int kVisualizeRasterizerStatistics = 1 << 1;\n        public static readonly int kDisplayEngineStatistics = 1 << 2;\n        public static readonly int kVisualizeEngineStatistics = 1 << 3;\n\n        public static SKColor SK_ColorTRANSPARENT = SKColor.Parse(\"#FF000000\");\n\n        internal const double kOneFrameMS = 1e3 / 60.0;\n\n        internal const int kMaxSamples = 120;\n        internal const int kMaxFrameMarkers = 8;\n\n        internal static double UnitFrameInterval(double frame_time_ms)\n        {\n            return frame_time_ms * 60.0 * 1e-3;\n        }\n\n        internal static double UnitHeight(double frame_time_ms, double max_unit_interval)\n        {\n            double unitHeight = UnitFrameInterval(frame_time_ms) / max_unit_interval;\n            if (unitHeight > 1.0)\n            {\n                unitHeight = 1.0;\n            }\n            return unitHeight;\n        }\n\n        internal static bool CanRasterizePicture(SKPicture picture)\n        {\n            if (picture == null)\n            {\n                return false;\n            }\n\n            SKRect cull_rect = picture.CullRect;\n\n            if (cull_rect.IsEmpty)\n            {\n                // No point in ever rasterizing an empty picture.\n                return false;\n            }\n\n            if (float.IsInfinity(cull_rect.Width) || float.IsInfinity(cull_rect.Height))\n            {\n                // Cannot attempt to rasterize into an infinitely large surface.\n                return false;\n            }\n\n            return true;\n        }\n\n        internal static bool IsPictureWorthRasterizing(SKPicture picture, bool will_change, bool is_complex)\n        {\n            if (will_change)\n            {\n                // If the picture is going to change in the future, there is no point in\n                // doing to extra work to rasterize.\n                return false;\n            }\n\n            if (!CanRasterizePicture(picture))\n            {\n                // No point in deciding whether the picture is worth rasterizing if it\n                // cannot be rasterized at all.\n                return false;\n            }\n\n            if (is_complex)\n            {\n                // The caller seems to have extra information about the picture and thinks\n                // the picture is always worth rasterizing.\n                return true;\n            }\n\n            // TODO(abarth): We should find a better heuristic here that lets us avoid\n            // wasting memory on trivial layers that are easy to re-rasterize every frame.\n            return false; //picture.approximateOpCount() > 10;\n        }\n\n        internal static RasterCacheResult Rasterize(GRContext context, SKMatrix ctm, SKColorSpace dst_color_space, bool checkerboard, SKRect logical_rect, Action<SKCanvas> draw_function)\n        {\n            SKRectI cache_rect = RasterCache.GetDeviceBounds(logical_rect, ctm);\n\n            SKImageInfo image_info = new SKImageInfo(cache_rect.Width, cache_rect.Height);\n\n            SKSurface surface = context != null ? SKSurface.CreateAsRenderTarget(context, new GRGlBackendTextureDesc() { Width = cache_rect.Width, Height = cache_rect.Height } ) : SKSurface.Create(image_info); //{ image_info.\n\n            if (surface == null)\n            {\n                return new RasterCacheResult();\n            }\n\n            SKCanvas canvas = surface.Canvas;\n            SKCanvas xformCanvas = canvas;\n            //if (dst_color_space != null)\n            //{\n            //    xformCanvas = SkCreateColorSpaceXformCanvas(canvas, GlobalMembers.sk_ref_sp(dst_color_space));\n            //    if (xformCanvas != null)\n            //    {\n            //        canvas = xformCanvas;\n            //    }\n            //}\n\n            canvas.Clear(GlobalMembers.SK_ColorTRANSPARENT);\n            canvas.Translate(-cache_rect.Left, -cache_rect.Top);\n            canvas.Concat(ref ctm);\n            draw_function(canvas);\n\n            //if (checkerboard)\n            //{\n            //    DrawCheckerboard(canvas, logical_rect);\n            //}\n\n            return new RasterCacheResult(surface.Snapshot(), logical_rect);\n        }\n\n        public static RasterCacheResult RasterizePicture(SKPicture picture, GRContext context, SKMatrix ctm, SKColorSpace dst_color_space, bool checkerboard)\n        {\n            TRACE_EVENT0(\"flutter\", \"RasterCachePopulate\");\n\n            return Rasterize(context, ctm, dst_color_space, checkerboard, picture.CullRect, (SKCanvas canvas) =>\n            {\n                canvas.DrawPicture(picture);\n            });\n        }\n\n        internal static int ClampSize(int value, int min, int max)\n        {\n            if (value > max)\n            {\n                return max;\n            }\n\n            if (value < min)\n            {\n                return min;\n            }\n\n            return value;\n        }\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/Helper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Flow\n{\n    public static class Helper\n    {\n\n        public static void TRACE_EVENT0(string source, string message)\n        { }\n\n        public static void FML_DCHECK(bool check)\n        { }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Flow/Layers/BackdropFilterLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class BackdropFilterLayer : ContainerLayer\n    {\n\n        public void set_filter(SKImageFilter filter)\n        {\n            filter_ = filter;\n        }\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"BackdropFilterLayer::Paint\");\n            FML_DCHECK(needs_painting());\n          \n            Layer.AutoSaveLayer save = Layer.AutoSaveLayer.Create(context, paint_bounds(), new SKPaint() { ImageFilter = filter_ }); //, null, filter_, 0);\n            PaintChildren(context);\n        }\n\n        private SKImageFilter filter_;\n    }\n\n}\n"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ChildSceneLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    // Layer that represents an embedded child.\n    public class ChildSceneLayer : Layer\n    {\n\n        public void set_offset(SKPoint offset)\n        {\n            offset_ = offset;\n        }\n\n        public void set_size(SKSize size)\n        {\n            size_ = size;\n        }\n\n        public void set_hit_testable(bool hit_testable)\n        {\n            hit_testable_ = hit_testable;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            set_needs_system_composite(true);\n        }\n\n        public override void Paint(PaintContext context)\n        {\n           // FXL_NOTREACHED() << \"This layer never needs painting.\";\n        }\n\n        private SKPoint offset_ = new SKPoint();\n        private SKSize size_ = new SKSize();\n        private bool hit_testable_ = true;\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ClipPathLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class ClipPathLayer : ContainerLayer\n    {\n        public ClipPathLayer(Clip clip_behavior = Clip.antiAlias)\n        {\n            this.clip_behavior_ = clip_behavior;\n        }\n\n        public void set_clip_path(SKPath clip_path)\n        {\n            clip_path_ = clip_path;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKRect child_paint_bounds = SKRect.Empty;\n            PrerollChildren(context, matrix, ref child_paint_bounds);\n\n            if (child_paint_bounds.IntersectsWith(clip_path_.Bounds))\n            {\n                set_paint_bounds(child_paint_bounds);\n            }\n        }\n\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"ClipPathLayer::Paint\");\n            FML_DCHECK(needs_painting());\n            \n            context.canvas.ClipPath(clip_path_, antialias: clip_behavior_ != Clip.hardEdge);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.SaveLayer(paint_bounds(), null);\n            }\n            PaintChildren(context);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.Restore();\n            }\n        }\n\n        private SKPath clip_path_ = new SKPath();\n        private Clip clip_behavior_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ClipRRectLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class ClipRRectLayer : ContainerLayer\n    {\n        public ClipRRectLayer(Clip clip_behavior)\n        {\n            this.clip_behavior_ = clip_behavior;\n        }\n\n        public void set_clip_rrect(SKRoundRect clip_rrect)\n        {\n            clip_rrect_ = clip_rrect;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKRect child_paint_bounds = SKRect.Empty;\n            PrerollChildren(context, matrix, ref child_paint_bounds);\n\n            if (child_paint_bounds.IntersectsWith(clip_rrect_.Rect))\n            {\n                set_paint_bounds(child_paint_bounds);\n            }\n        }\n               \n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"ClipRRectLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            context.canvas.ClipRoundRect(clip_rrect_, antialias: clip_behavior_ != Clip.hardEdge);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.SaveLayer(paint_bounds(), null);\n            }\n            PaintChildren(context);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.Restore();\n            }\n        }\n\n        private SKRoundRect clip_rrect_;\n        private Clip clip_behavior_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ClipRectLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class ClipRectLayer : ContainerLayer\n    {\n        public ClipRectLayer(Clip clip_behavior)\n        {\n            this.clip_behavior_ = clip_behavior;\n        }\n\n        public void set_clip_rect(SKRect clip_rect)\n        {\n            clip_rect_=clip_rect;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKRect child_paint_bounds = SKRect.Empty;\n            PrerollChildren(context, matrix, ref child_paint_bounds);\n\n            if (child_paint_bounds.IntersectsWith(clip_rect_))\n            {\n                set_paint_bounds(child_paint_bounds);\n            }\n        }\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"ClipRectLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            context.canvas.ClipRect(paint_bounds(), antialias: clip_behavior_ != Clip.hardEdge);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.SaveLayer(paint_bounds(), null);\n            }\n            PaintChildren(context);\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.Restore();\n            }\n        }\n\n        private SKRect clip_rect_ = new SKRect();\n        private Clip clip_behavior_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ColorFilterLayer.cs",
    "content": "﻿using SkiaSharp;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class ColorFilterLayer : ContainerLayer\n    {\n\n        public void set_color(uint color)\n        {\n            color_ = color;\n        }\n\n        public void set_blend_mode(SKBlendMode blend_mode)\n        {\n            blend_mode_ = blend_mode;\n        }\n        \n        public override void Paint(PaintContext context)\n        {\n\n            var color_filter = SKColorFilter.CreateBlendMode(color_, blend_mode_);\n            SKPaint paint = new SKPaint();\n            paint.ColorFilter = color_filter;\n\n            Layer.AutoSaveLayer save = Layer.AutoSaveLayer.Create(context, paint_bounds(), paint);\n            PaintChildren(context);\n        }\n\n        private uint color_;\n        private SKBlendMode blend_mode_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ContainerLayer.cs",
    "content": "﻿using SkiaSharp;\nusing System.Collections.Generic;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public abstract class ContainerLayer : Layer\n    {\n\n        public void Add(Layer layer)\n        {\n            layer.set_parent(this);\n            layers_.Add(layer);\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            TRACE_EVENT0(\"flutter\", \"ContainerLayer::Preroll\");\n\n            SKRect child_paint_bounds = SKRect.Empty;\n            PrerollChildren(context, matrix, ref child_paint_bounds);\n            set_paint_bounds(child_paint_bounds);\n        }\n        public List<Layer> layers()\n        {\n            return layers_;\n        }\n\n        protected void PrerollChildren(PrerollContext context, SKMatrix child_matrix, ref SKRect child_paint_bounds)\n        {\n            foreach (var layer in layers_)\n            {\n                PrerollContext child_context = context;\n                layer.Preroll(child_context, child_matrix);\n\n                if (layer.needs_system_composite())\n                {\n                    set_needs_system_composite(true);\n                }\n                child_paint_bounds.Union(layer.paint_bounds());\n            }\n        }\n        protected void PaintChildren(PaintContext context)\n        {\n            FML_DCHECK(needs_painting());\n\n            // Intentionally not tracing here as there should be no self-time\n            // and the trace event on this common function has a small overhead.\n            foreach (var layer in layers_)\n            {\n                if (layer.needs_painting())\n                {\n                    layer.Paint(context);\n                }\n            }\n        }\n\n        public List<Layer> layers_ = new List<Layer>();\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/LayerTree.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class LayerTree\n    {\n        public LayerTree()\n        {\n            this.frame_size_ = new SKSizeI();\n            this.rasterizer_tracing_threshold_ = 0;\n            this.checkerboard_raster_cache_images_ = false;\n            this.checkerboard_offscreen_layers_ = false;\n        }\n\n        public void Preroll(CompositorContext.ScopedFrame frame, bool ignore_raster_cache = false)\n        {\n            TRACE_EVENT0(\"flutter\", \"LayerTree::Preroll\");\n            \n            //TODO: frame.canvas().imageInfo().colorSpace()\n            SKColorSpace color_space = frame.canvas() != null ? SKImageInfo.Empty.ColorSpace : null;\n            frame.context().raster_cache().SetCheckboardCacheImages(checkerboard_raster_cache_images_);\n            PrerollContext context = ignore_raster_cache ? null :new PrerollContext(frame.context().raster_cache(), frame.gr_context(), color_space, SKRect.Empty, frame.context().texture_registry(), checkerboard_offscreen_layers_);\n\n            root_layer_.Preroll(context, frame.root_surface_transformation());\n        }\n\n        public void Paint(CompositorContext.ScopedFrame frame, bool ignore_raster_cache = false)\n        {\n            TRACE_EVENT0(\"flutter\", \"LayerTree::Paint\");\n            Layer.PaintContext context = new Layer.PaintContext(frame.canvas(), frame.view_embedder(), frame.context().texture_registry(), ignore_raster_cache ? null : frame.context().raster_cache(), checkerboard_offscreen_layers_);\n\n            if (root_layer_.needs_painting())\n            {\n                root_layer_.Paint(context);\n            }\n        }\n\n        public SKPicture Flatten(SKRect bounds)\n        {\n            TRACE_EVENT0(\"flutter\", \"LayerTree::Flatten\");\n\n            SKPictureRecorder recorder = new SKPictureRecorder();\n            var canvas = recorder.BeginRecording(bounds);\n\n            if (canvas == null)\n            {\n                return null;\n            }\n\n            TextureRegistry unused_texture_registry = new TextureRegistry();\n            SKMatrix root_surface_transformation = new SKMatrix();\n            // No root surface transformation. So assume identity.\n            canvas.ResetMatrix();\n\n            PrerollContext preroll_context = new PrerollContext(null, null, null, SKRect.Empty, unused_texture_registry, false);\n\n            Layer.PaintContext paint_context = new Layer.PaintContext(canvas, null, unused_texture_registry, null, false);\n\n            // Even if we don't have a root layer, we still need to create an empty\n            // picture.\n            if (root_layer_ != null)\n            {\n                root_layer_.Preroll(preroll_context, root_surface_transformation);\n                // The needs painting flag may be set after the preroll. So check it after.\n                if (root_layer_.needs_painting())\n                {\n                    root_layer_.Paint(paint_context);\n                }\n            }\n\n            return recorder.EndRecording();\n        }\n\n        public void set_root_layer(Layer root_layer)\n        {\n            root_layer_ = root_layer;\n        }\n\n        public SKSizeI frame_size()\n        {\n            return frame_size_;\n        }\n\n        public void set_frame_size(SKSizeI frame_size)\n        {\n            frame_size_ = frame_size;\n        }\n\n        // The number of frame intervals missed after which the compositor must\n        // trace the rasterized picture to a trace file. Specify 0 to disable all\n        // tracing\n        public void set_rasterizer_tracing_threshold(uint interval)\n        {\n            rasterizer_tracing_threshold_ = interval;\n        }\n        public uint rasterizer_tracing_threshold()\n        {\n            return rasterizer_tracing_threshold_;\n        }\n\n        public void set_checkerboard_raster_cache_images(bool checkerboard)\n        {\n            checkerboard_raster_cache_images_ = checkerboard;\n        }\n\n        public void set_checkerboard_offscreen_layers(bool checkerboard)\n        {\n            checkerboard_offscreen_layers_ = checkerboard;\n        }\n\n        private SKSizeI frame_size_ = new SKSizeI(); // Physical pixels.\n        public Layer root_layer_;\n        private uint rasterizer_tracing_threshold_;\n        private bool checkerboard_raster_cache_images_;\n        private bool checkerboard_offscreen_layers_;\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/OpacityLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class OpacityLayer : ContainerLayer\n    {\n\n        public void set_alpha(int alpha)\n        {\n            alpha_ = alpha;\n        }\n        public void set_offset(SKPoint offset)\n        {\n            offset_ = offset;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKMatrix child_matrix = matrix;\n            child_matrix.SetScaleTranslate(child_matrix.ScaleX, child_matrix.ScaleY, offset_.X, offset_.Y);\n            base.Preroll(context, child_matrix);\n            if (context.raster_cache != null && layers().Count == 1)\n            {\n                Layer child = layers()[0];//.get();\n                SKMatrix ctm = child_matrix;\n\n#if !SUPPORT_FRACTIONAL_TRANSLATION\n                ctm = RasterCache.GetIntegralTransCTM(ctm);\n#endif\n                context.raster_cache.Prepare(context, child, ctm);\n            }\n        }\n\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"OpacityLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            SKPaint paint = new SKPaint();\n            paint.Color = paint.Color.WithAlpha((byte)alpha_);\n\n            context.canvas.Translate(offset_.X, offset_.Y);\n\n#if !SUPPORT_FRACTIONAL_TRANSLATION\n            context.canvas.SetMatrix(RasterCache.GetIntegralTransCTM(context.canvas.TotalMatrix));\n#endif\n\n            if (layers().Count == 1 && context.raster_cache != null)\n            {\n                SKMatrix ctm = context.canvas.TotalMatrix;\n                RasterCacheResult child_cache = context.raster_cache.Get(layers()[0], ctm);\n                if (child_cache.is_valid)\n                {\n                    child_cache.draw(context.canvas, paint);\n                    return;\n                }\n            }\n\n            Layer.AutoSaveLayer save_layer = Layer.AutoSaveLayer.Create(context, paint_bounds(), paint);\n            PaintChildren(context);\n        }\n\n        // TODO(chinmaygarde): Once MZ-139 is addressed, introduce a new node in the\n        // session scene hierarchy.\n\n        private int alpha_;\n        private SKPoint offset_ = new SKPoint();\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/PhysicalShapeLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2017 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class PhysicalShapeLayer : ContainerLayer\n    {\n        public PhysicalShapeLayer(Clip clip_behavior)\n        {\n            this.isRect_ = false;\n            this.clip_behavior_ = clip_behavior;\n        }\n\n        public void set_path(SKPath path)\n        {\n            \n            path_ = path;\n            isRect_ = false;\n            SKRect rect = new SKRect();\n\n            // Awaiting API implementation in SkiaSharp\n\n            //if (path.isRect(rect))\n            //{\n            //    isRect_ = true;\n            //    frameRRect_ = new SKRoundRect(rect);\n            //}\n            //else if (SKPath.path.isRRect(frameRRect_))\n            //{\n            //    isRect_ = frameRRect_.isRect();\n            //}\n            //else if (path.isOval(rect))\n            //{\n            //    // isRRect returns false for ovals, so we need to explicitly check isOval\n            //    // as well.\n            //    frameRRect_ = new SKRoundRect(rect);\n            //}\n            //else\n            //{\n                // Scenic currently doesn't provide an easy way to create shapes from\n                // arbitrary paths.\n                // For shapes that cannot be represented as a rounded rectangle we\n                // default to use the bounding rectangle.\n                // TODO(amirh): fix this once we have a way to create a Scenic shape from\n                // an SKPath.\n                frameRRect_ = new SKRoundRect(path.Bounds);\n            //}\n        }\n\n        public void set_elevation(float elevation)\n        {\n            elevation_ = elevation;\n        }\n        public void set_color(uint color)\n        {\n            color_ = color;\n        }\n        public void set_shadow_color(uint shadow_color)\n        {\n            shadow_color_ = shadow_color;\n        }\n        public void set_device_pixel_ratio(float dpr)\n        {\n            device_pixel_ratio_ = dpr;\n        }\n\n        public static void DrawShadow(SKCanvas canvas, SKPath path, uint color, float elevation, bool transparentOccluder, float dpr)\n        {\n            const float kAmbientAlpha = 0.039f;\n            const float kSpotAlpha = 0.25f;\n            const float kLightHeight = 600F;\n            const float kLightRadius = 800F;\n\n            //SkShadowFlags flags = transparentOccluder ? SkShadowFlags.kTransparentOccluder_ShadowFlag : SkShadowFlags.kNone_ShadowFlag;\n            //SKRect bounds = path.Bounds;\n            //float shadow_x = (bounds.Left + bounds.Right) / 2;\n            //float shadow_y = bounds.Top - 600.0f;\n            //uint inAmbient = GlobalMembers.SkColorSetA(color, kAmbientAlpha * (((color) >> 24) & 0xFF));\n            //uint inSpot = GlobalMembers.SkColorSetA(color, kSpotAlpha * (((color) >> 24) & 0xFF));\n            //uint ambientColor;\n            //uint spotColor;\n            //SkShadowUtils.ComputeTonalColors(inAmbient, inSpot, ref ambientColor, ref spotColor);\n            //SkShadowUtils.DrawShadow(canvas, path, SKPoint3.Make(0, 0, dpr * elevation), SKPoint3.Make(shadow_x, shadow_y, dpr * kLightHeight), dpr * kLightRadius, ambientColor, spotColor, flags);\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKRect child_paint_bounds = new SKRect();\n            PrerollChildren(context, matrix, ref child_paint_bounds);\n\n            if (elevation_ == 0F)\n            {\n                set_paint_bounds(path_.Bounds);\n            }\n            else\n            {\n                // Add some margin to the paint bounds to leave space for the shadow.\n                // The margin is hardcoded to an arbitrary maximum for now because Skia\n                // doesn't provide a way to calculate it.  We fill this whole region\n                // and clip children to it so we don't need to join the child paint bounds.\n                SKRect bounds = path_.Bounds;\n                bounds.Offset(20.0f, 20.0f);\n                set_paint_bounds(bounds);\n            }\n        }\n\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"PhysicalShapeLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            if (elevation_ != 0F)\n            {\n                DrawShadow(context.canvas, path_, shadow_color_, elevation_, (((color_) >> 24) & 0xFF) != 0xff, device_pixel_ratio_);\n            }\n\n            // Call drawPath without clip if possible for better performance.\n            SKPaint paint = new SKPaint();\n            paint.Color = color_;\n            if (clip_behavior_ != Clip.antiAliasWithSaveLayer)\n            {\n                context.canvas.DrawPath(path_, paint);\n            }\n\n            int saveCount = context.canvas.Save();\n            switch (clip_behavior_)\n            {\n                case Clip.hardEdge:\n                    context.canvas.ClipPath(path_, antialias: false);\n                    break;\n                case Clip.antiAlias:\n                    context.canvas.ClipPath(path_, antialias: true);\n                    break;\n                case Clip.antiAliasWithSaveLayer:\n                    context.canvas.ClipPath(path_, antialias: true);\n                    context.canvas.SaveLayer(paint_bounds(), null);\n                    break;\n                case Clip.none:\n                    break;\n            }\n\n            if (clip_behavior_ == Clip.antiAliasWithSaveLayer)\n            {\n                // If we want to avoid the bleeding edge artifact\n                // (https://github.com/flutter/flutter/issues/18057#issue-328003931)\n                // using saveLayer, we have to call drawPaint instead of drawPath as\n                // anti-aliased drawPath will always have such artifacts.\n                context.canvas.DrawPaint(paint);\n            }\n\n            PaintChildren(context);\n\n            context.canvas.RestoreToCount(saveCount);\n        }\n\n\n        private float elevation_;\n        private uint color_;\n        private uint shadow_color_;\n        private float device_pixel_ratio_;\n        private SKPath path_ = new SKPath();\n        private bool isRect_;\n        private SKRoundRect frameRRect_ = new SKRoundRect();\n        private Clip clip_behavior_;\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/PictureLayer.cs",
    "content": "﻿using static FlutterBinding.Flow.Helper;\nusing SkiaSharp;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class PictureLayer : Layer\n    {\n\n        public void set_offset(SKPoint offset)\n        {\n            offset_ = offset;\n        }\n        public void set_picture(SKPicture picture)\n        {\n            picture_ = picture;\n        }\n\n        public void set_is_complex(bool value)\n        {\n            is_complex_ = value;\n        }\n        public void set_will_change(bool value)\n        {\n            will_change_ = value;\n        }\n\n        public SKPicture picture()\n        {\n            return picture_;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKPicture sk_picture = picture();\n\n            var cache = context.raster_cache;\n            SKMatrix ctm = matrix;\n            \n            ctm.SetScaleTranslate(ctm.ScaleX, ctm.ScaleY, offset_.X, offset_.Y);\n#if !SUPPORT_FRACTIONAL_TRANSLATION\n            ctm = RasterCache.GetIntegralTransCTM(ctm);\n#endif\n            cache.Prepare(context.gr_context, sk_picture, ctm, context.dst_color_space, is_complex_, will_change_);\n\n\n            SKRect bounds = sk_picture.CullRect;\n            bounds.Offset(offset_.X, offset_.Y);\n            set_paint_bounds(bounds);\n        }\n\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"PictureLayer::Paint\");\n            //FML_DCHECK(picture_);\n            FML_DCHECK(needs_painting());\n\n            context.canvas.Translate(offset_.X, offset_.Y);\n#if !SUPPORT_FRACTIONAL_TRANSLATION\n            context.canvas.SetMatrix(RasterCache.GetIntegralTransCTM(context.canvas.TotalMatrix));\n#endif\n\n            if (context.raster_cache != null)\n            {\n                SKMatrix ctm = context.canvas.TotalMatrix;\n                RasterCacheResult result = context.raster_cache.Get(picture(), ctm);\n                if (result.is_valid)\n                {\n                    result.draw(context.canvas);\n                    return;\n                }\n            }\n            context.canvas.DrawPicture(picture());\n        }\n\n        private SKPoint offset_ = new SKPoint();\n        // Even though pictures themselves are not GPU resources, they may reference\n        // images that have a reference to a GPU resource.\n        private SKPicture picture_;\n        private bool is_complex_ = false;\n        private bool will_change_ = false;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/PlatformViewLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2018 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class PlatformViewLayer : Layer\n    {\n\n        public void set_offset(SKPoint offset)\n        {\n            offset_ = offset;\n        }\n        public void set_size(SKSize size)\n        {\n            size_ = size;\n        }\n        public void set_view_id(ulong view_id)\n        {\n            view_id_ = view_id;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            set_paint_bounds(new SKRect(offset_.X, offset_.Y, size_.Width, size_.Height));\n        }\n        public override void Paint(PaintContext context)\n        {\n            if (context.view_embedder == null)\n            {\n                return;\n            }\n            EmbeddedViewParams @params = new EmbeddedViewParams();\n            SKMatrix transform = context.canvas.TotalMatrix;\n            @params.offsetPixels = new SKPoint(transform.TransX, transform.TransY);\n            @params.sizePoints = size_;\n\n            context.view_embedder.CompositeEmbeddedView(view_id_, @params);\n        }\n\n        private SKPoint offset_ = new SKPoint();\n        private SKSize size_ = new SKSize();\n        private ulong view_id_ = new ulong();\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/ShaderMaskLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class ShaderMaskLayer : ContainerLayer\n    {\n\n        public void set_shader(SKShader shader)\n        {\n            shader_ = shader;\n        }\n\n        public void set_mask_rect(SKRect mask_rect)\n        {\n            mask_rect_ = mask_rect;\n        }\n\n        public void set_blend_mode(SKBlendMode blend_mode)\n        {\n            blend_mode_ = blend_mode;\n        }\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"ShaderMaskLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            Layer.AutoSaveLayer save = Layer.AutoSaveLayer.Create(context, paint_bounds(), null);\n            PaintChildren(context);\n\n            SKPaint paint = new SKPaint();\n            paint.BlendMode = blend_mode_;\n            paint.Shader = shader_;\n            context.canvas.Translate(mask_rect_.Left, mask_rect_.Top);\n            context.canvas.DrawRect(new SKRect(0, 0, mask_rect_.Width, mask_rect_.Height), paint);\n        }\n\n        private SKShader shader_;\n        private SKRect mask_rect_;\n        private SKBlendMode blend_mode_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/TextureLayer.cs",
    "content": "﻿using static FlutterBinding.Flow.Helper;\nusing SkiaSharp;\n\n// Copyright 2017 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class TextureLayer : Layer\n    {\n\n        public void set_offset(SKPoint offset)\n        {\n            offset_ = offset;\n        }\n        public void set_size(SKSize size)\n        {\n            size_ = size;\n        }\n        public void set_texture_id(ulong texture_id)\n        {\n            texture_id_ = texture_id;\n        }\n        public void set_freeze(bool freeze)\n        {\n            freeze_ = freeze;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            set_paint_bounds(new SKRect(offset_.X, offset_.Y, size_.Width, size_.Height));\n        }\n        public override void Paint(PaintContext context)\n        {\n            Texture texture = context.texture_registry.GetTexture(texture_id_);\n            if (texture == null)\n            {\n                return;\n            }\n            texture.Paint(context.canvas, paint_bounds(), freeze_);\n        }\n\n        private SKPoint offset_ = new SKPoint();\n        private SKSize size_ = new SKSize();\n        private ulong texture_id_ = new ulong();\n        private bool freeze_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/Layers/TransformLayer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    public class TransformLayer : ContainerLayer\n    {\n\n        public void set_transform(SKMatrix transform)\n        {\n            transform_ = transform;\n        }\n\n        public override void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n            SKMatrix child_matrix = new SKMatrix();\n            SKMatrix.Concat(ref child_matrix, matrix, transform_);\n            \n            SKRect child_paint_bounds = SKRect.Empty;\n            PrerollChildren(context, child_matrix, ref child_paint_bounds);\n\n            transform_.MapRect(child_paint_bounds);\n            set_paint_bounds(child_paint_bounds);\n        }\n\n        public override void Paint(PaintContext context)\n        {\n            TRACE_EVENT0(\"flutter\", \"TransformLayer::Paint\");\n            FML_DCHECK(needs_painting());\n\n            context.canvas.Concat(ref transform_);\n            PaintChildren(context);\n        }\n\n        private SKMatrix transform_ = new SKMatrix();\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/MatrixDecomposition.cs",
    "content": "﻿using static FlutterBinding.Flow.Helper;\n\n// Copyright 2017 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"
  },
  {
    "path": "FlutterBinding/Flow/PaintUtils.cs",
    "content": "﻿using static FlutterBinding.Flow.Helper;\n\n// Copyright 2017 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"
  },
  {
    "path": "FlutterBinding/Flow/RasterCache.cs",
    "content": "﻿using FlutterBinding.Flow.Layers;\nusing SkiaSharp;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static FlutterBinding.Flow.RasterCache;\n\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\nnamespace FlutterBinding.Flow\n{\n\n    public class RasterCacheResult\n    {\n        public RasterCacheResult()\n        {\n        }\n\n        public RasterCacheResult(SKImage image, SKRect logical_rect)\n        {\n            this.image_ = image;\n            this.logical_rect_ = new SKRect(logical_rect.Left, logical_rect.Top, logical_rect.Right, logical_rect.Bottom);\n        }\n\n        public bool is_valid => image_ != null; //?? I'm not sure if this is right\n       \n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: void draw(SKCanvas& canvas, const SKPaint* paint = null) const\n        public void draw(SKCanvas canvas, SKPaint paint = null)\n        {\n            var bounds = RasterCache.GetDeviceBounds(logical_rect_, canvas.TotalMatrix);\n            canvas.ResetMatrix();\n            canvas.DrawImage(image_, bounds.Left, bounds.Top, paint);\n        }\n\n        private SKImage image_;\n        private SKRect logical_rect_;\n    }\n    \n    public class UniqueEntry : Entry\n    {\n        public UniqueEntry(uint value) => Value = value;\n        public uint Value { get; private set; }\n    }\n\n\n    public class RasterCache //: System.IDisposable\n    {\n        public RasterCache(int threshold = 3)\n        {\n            this.threshold_ = threshold;\n            this.checkerboard_images_ = false;\n            this.weak_factory_ = this;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        public static SKRectI GetDeviceBounds(SKRect rect, SKMatrix ctm)\n        {\n            SKRect device_rect = new SKRect();\n            SKMatrix.MapRect(ref ctm, out device_rect, ref rect);\n            var bounds = SKRectI.Round(device_rect);      \n            return bounds;\n        }\n\n        public static SKMatrix GetIntegralTransCTM(SKMatrix ctm)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n            //ORIGINAL LINE: SKMatrix result = ctm;\n            SKMatrix result = ctm;\n            result.TransX = (float)Math.Floor((ctm.TransX) + 0.5f);\n            result.TransY = (float)Math.Floor((ctm.TransY) + 0.5f);\n            return result;\n        }\n\n        // Return true if the cache is generated.\n        //\n        // We may return false and not generate the cache if\n        // 1. The picture is not worth rasterizing\n        // 2. The matrix is singular\n        // 3. The picture is accessed too few times\n        public bool Prepare(GRContext context, SKPicture picture, SKMatrix transformation_matrix, SKColorSpace dst_color_space, bool is_complex, bool will_change)\n        {\n            if (!GlobalMembers.IsPictureWorthRasterizing(picture, will_change, is_complex))\n            {\n                // We only deal with pictures that are worthy of rasterization.\n                return false;\n            }\n\n            // Decompose the matrix (once) for all subsequent operations. We want to make\n            // sure to avoid volumetric distortions while accounting for scaling.\n            //MatrixDecomposition matrix = new MatrixDecomposition(transformation_matrix);\n\n            //if (!matrix.IsValid())\n            //{\n            //    // The matrix was singular. No point in going further.\n            //    return false;\n            //}\n\n            RasterCacheKey<UniqueEntry> cache_key = new RasterCacheKey<UniqueEntry>(new UniqueEntry(picture.UniqueId), transformation_matrix);\n\n            Entry entry = picture_cache_.First(x => x.Equals(cache_key)).id(); // I used Linq, that aint going to be good for performance\n            entry.access_count = GlobalMembers.ClampSize(entry.access_count + 1, 0, threshold_);\n            entry.used_this_frame = true;\n\n            if (entry.access_count < threshold_ || threshold_ == 0)\n            {\n                // Frame threshold has not yet been reached.\n                return false;\n            }\n\n            if (!entry.image.is_valid)\n            {\n                entry.image = GlobalMembers.RasterizePicture(picture, context, transformation_matrix, dst_color_space, checkerboard_images_);\n            }\n            return true;\n        }\n\n        public void Prepare(PrerollContext context, Layer layer, SKMatrix ctm)\n        {\n            RasterCacheKey<Layer> cache_key = new RasterCacheKey<Layer>(layer, ctm);\n            Entry entry = layer_cache_.First(x=>x == cache_key).id(); // I used Linq, that aint going to be good for performance\n         \n            entry.access_count = GlobalMembers.ClampSize(entry.access_count + 1, 0, threshold_);\n            entry.used_this_frame = true;\n            if (!entry.image.is_valid)\n            {\n                entry.image = GlobalMembers.Rasterize(context.gr_context, ctm, context.dst_color_space, checkerboard_images_, layer.paint_bounds(), (SKCanvas canvas) =>\n                {\n                    Layer.PaintContext paintContext = new Layer.PaintContext(canvas, null, context.texture_registry, context.raster_cache, context.checkerboard_offscreen_layers);\n                    layer.Paint(paintContext);\n                });\n            }\n        }\n\n        public RasterCacheResult Get(SKPicture picture, SKMatrix ctm)\n        {\n            var cache_key = new RasterCacheKey<UniqueEntry>(new UniqueEntry(picture.UniqueId), ctm);\n            var it = picture_cache_.First(x => x.Equals(cache_key));\n            return it == picture_cache_.Last() ? new RasterCacheResult() : new RasterCacheResult(); // This aint right;\n        }\n        \n        public RasterCacheResult Get(Layer layer, SKMatrix ctm)\n        {\n            //RasterCacheKey<Layer> cache_key = new RasterCacheKey<Layer>(layer, ctm);\n            //var it = layer_cache_.find(cache_key);\n            return new RasterCacheResult(); // This aint right;\n            //return it == layer_cache_.end() ? new RasterCacheResult() : it.second.image;\n        }\n\n        public void SweepAfterFrame()\n        {\n            SweepOneCacheAfterFrame(picture_cache_);\n            SweepOneCacheAfterFrame(layer_cache_);\n        }\n\n        public void Clear()\n        {\n            picture_cache_.Clear();\n        }\n\n        public void SetCheckboardCacheImages(bool checkerboard)\n        {\n            if (checkerboard_images_ == checkerboard)\n            {\n                return;\n            }\n\n            checkerboard_images_ = checkerboard;\n\n            // Clear all existing entries so previously rasterized items (with or without\n            // a checkerboard) will be refreshed in subsequent passes.\n            Clear();\n        }\n\n        public class Entry\n        {\n            public bool used_this_frame = false;\n            public int access_count = 0;\n            public RasterCacheResult image = new RasterCacheResult();\n        }\n\n        private static void SweepOneCacheAfterFrame<Cache>(List<RasterCacheKey<Cache>> cache) where Cache : Entry\n        {\n            var dead = new List<RasterCacheKey<Cache>>();\n\n            for (int i = 0; i < cache.Count; i++)\n            {\n                Entry entry = cache[i].id();\n                if (!entry.used_this_frame)\n                {\n                    dead.Add(cache[i]);\n                }\n                entry.used_this_frame = false;\n            }\n\n            foreach (var it in dead)\n            {\n                cache.Remove(it);\n            }\n        }\n\n        private readonly int threshold_ = new int();\n        private List<RasterCacheKey<Entry>> picture_cache_ = new List<RasterCacheKey<Entry>>(); // = new PictureRasterCacheKey.Map<Entry>();\n        private List<RasterCacheKey<Layer>> layer_cache_ = new List<RasterCacheKey<Layer>>(); // new LayerRasterCacheKey.Map<Entry>();\n        private bool checkerboard_images_;\n        private RasterCache weak_factory_;\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/RasterCacheKey.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\nusing static FlutterBinding.Flow.RasterCache;\n\n// Copyright 2017 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\nnamespace FlutterBinding.Flow\n{\n\n    public class RasterCacheKey<ID> where ID : Entry\n    {\n        public RasterCacheKey(ID id, SKMatrix ctm)\n        {\n            this.id_ = id;\n            this.matrix_ = ctm;\n#if !SUPPORT_FRACTIONAL_TRANSLATION\n            FML_DCHECK(ctm.TransX == 0F && ctm.TransY == 0F);\n#endif\n        }\n\n        public ID id()\n        {\n            return id_;\n        }\n\n        public SKMatrix matrix()\n        {\n            return matrix_;\n        }\n\n        public class Hash\n        {\n            public static uint functorMethod(RasterCacheKey<ID> key)\n            {\n               return (uint)key.GetHashCode();\n            }\n        }\n\n        public class Equal\n        {\n            public static bool functorMethod(RasterCacheKey<ID> lhs, RasterCacheKey<ID> rhs)\n            {\n                return lhs.id_.Equals(rhs.id_) && lhs.matrix_.Equals(rhs.matrix_);\n            }\n        }\n\n        private ID id_;\n        private SKMatrix matrix_ = new SKMatrix();\n    }\n}"
  },
  {
    "path": "FlutterBinding/Flow/layers/layer.cs",
    "content": "﻿using SkiaSharp;\nusing static FlutterBinding.Flow.Helper;\nusing static FlutterBinding.Flow.RasterCache;\n\n// Copyright 2015 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\nnamespace FlutterBinding.Flow.Layers\n{\n\n    // This should be an exact copy of the Clip enum in painting.dart.\n    public enum Clip\n    {\n        none,\n        hardEdge,\n        antiAlias,\n        antiAliasWithSaveLayer\n    }\n\n    public class PrerollContext\n    {\n        public RasterCache raster_cache;\n        public GRContext gr_context;\n        public SKColorSpace dst_color_space;\n        public SKRect child_paint_bounds = new SKRect();\n\n        // The following allows us to paint in the end of subtree preroll\n        public TextureRegistry texture_registry;\n        public readonly bool checkerboard_offscreen_layers;\n\n        public PrerollContext(RasterCache raster_cache,\n                              GRContext gr_context,\n                              SKColorSpace dst_color_space,\n                              SKRect child_paint_bounds,\n                              TextureRegistry texture_registry,\n                              bool checkerboard_offscreen_layers)\n        {\n            this.raster_cache = raster_cache;\n\n            if (raster_cache == null)\n                this.raster_cache = new RasterCache();\n\n            this.gr_context = gr_context;\n            this.dst_color_space = dst_color_space;\n            this.child_paint_bounds = child_paint_bounds;\n            this.texture_registry = texture_registry;\n            this.checkerboard_offscreen_layers = checkerboard_offscreen_layers;\n        }\n\n    }\n\n    // Represents a single composited layer. Created on the UI thread but then\n    // subquently used on the Rasterizer thread.\n    public abstract class Layer: Entry\n    {\n        public Layer()\n        {\n            this.parent_ = null;\n            this.needs_system_composite_ = false;\n            this.paint_bounds_ = SKRect.Empty;\n        }\n\n        public virtual void Preroll(PrerollContext context, SKMatrix matrix)\n        {\n        }\n\n        public class PaintContext\n        {\n            public SKCanvas canvas;\n            public ExternalViewEmbedder view_embedder;\n            public TextureRegistry texture_registry;\n            public readonly RasterCache raster_cache;\n            public readonly bool checkerboard_offscreen_layers;\n\n            public PaintContext(SKCanvas canvas,\n                                ExternalViewEmbedder view_embedder,\n                                TextureRegistry texture_registry,\n                                RasterCache raster_cache,\n                                bool checkerboard_offscreen_layers)\n            {\n                this.canvas = canvas;\n                this.view_embedder = view_embedder;\n                this.texture_registry = texture_registry;\n                this.raster_cache = raster_cache;\n                this.checkerboard_offscreen_layers = checkerboard_offscreen_layers;\n            }\n        }\n\n        // Calls SKCanvas::saveLayer and restores the layer upon destruction. Also\n        // draws a checkerboard over the layer if that is enabled in the PaintContext.\n        public class AutoSaveLayer : System.IDisposable\n        {\n            public static Layer.AutoSaveLayer Create(PaintContext paint_context, SKRect bounds, SKPaint paint)\n            {\n                return new Layer.AutoSaveLayer(paint_context, bounds, paint);\n            }\n\n            //public static Layer.AutoSaveLayer Create(PaintContext paint_context, SKCanvas.SaveLayerRec layer_rec)\n            //{\n            //    return new Layer.AutoSaveLayer(paint_context, layer_rec);\n            //}\n\n            public void Dispose()\n            {\n                if (paint_context_.checkerboard_offscreen_layers)\n                {\n                    //DrawCheckerboard(paint_context_.canvas, bounds_);\n                }\n                paint_context_.canvas.Restore();\n            }\n\n            private AutoSaveLayer(PaintContext paint_context, SKRect bounds, SKPaint paint)\n            {\n                this.paint_context_ = paint_context;\n                this.bounds_ = bounds;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n                //ORIGINAL LINE: paint_context_.canvas.saveLayer(bounds_, paint);\n                paint_context_.canvas.SaveLayer(bounds_, paint);\n            }\n\n            //private AutoSaveLayer(PaintContext paint_context, SKCanvas.SaveLayerRec layer_rec)\n            //{\n            //    this.paint_context_ = paint_context;\n            //    this.bounds_ = layer_rec.fBounds;\n            //    paint_context_.canvas.SaveLayer(layer_rec);\n            //}\n\n            private readonly PaintContext paint_context_;\n            private readonly SKRect bounds_ = new SKRect();\n        }\n\n        public abstract void Paint(PaintContext context);\n\n        public ContainerLayer parent()\n        {\n            return parent_;\n        }\n\n        public void set_parent(ContainerLayer parent)\n        {\n            parent_ = parent;\n        }\n\n        public bool needs_system_composite()\n        {\n            return needs_system_composite_;\n        }\n        public void set_needs_system_composite(bool value)\n        {\n            needs_system_composite_ = value;\n        }\n\n        public SKRect paint_bounds()\n        {\n            return paint_bounds_;\n        }\n\n        // This must be set by the time Preroll() returns otherwise the layer will\n        // be assumed to have empty paint bounds (paints no content).\n        public void set_paint_bounds(SKRect paint_bounds)\n        {\n            paint_bounds_ = paint_bounds;\n        }\n        public bool needs_painting()\n        {\n            return !paint_bounds_.IsEmpty;\n        }\n\n        private ContainerLayer parent_;\n        private bool needs_system_composite_;\n        private SKRect paint_bounds_ = new SKRect();\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Flow/texture.cs",
    "content": "﻿using SkiaSharp;\nusing System.Collections.Generic;\nusing static FlutterBinding.Flow.Helper;\n\n// Copyright 2017 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\nnamespace FlutterBinding.Flow\n{\n\n    public abstract class Texture\n    {\n        protected Texture(ulong id)\n        {\n            this.id_ = id;\n        }\n\n        // Called from GPU thread.\n        public abstract void Paint(SKCanvas canvas, SKRect bounds, bool freeze);\n\n        // Called from GPU thread.\n        public abstract void OnGRContextCreated();\n\n        // Called from GPU thread.\n        public abstract void OnGRContextDestroyed();\n\n        // Called on GPU thread.\n        public abstract void MarkNewFrameAvailable();\n\n        public ulong Id()\n        {\n            return id_;\n        }\n\n        private ulong id_ = new ulong();\n\n    }\n\n    public class TextureRegistry\n    {\n\n        // Called from GPU thread.\n        public void RegisterTexture(Texture texture)\n        {\n            mapping_[texture.Id()] = texture;\n        }\n\n        // Called from GPU thread.\n        public void UnregisterTexture(ulong id)\n        {\n            mapping_.Remove(id);\n        }\n\n        // Called from GPU thread.\n        public Texture GetTexture(ulong id)\n        {\n            var it = mapping_[id];\n            return it; //: null; // This isn't right either\n        }\n\n        // Called from GPU thread.\n        public void OnGRContextCreated()\n        {\n            foreach (var it in mapping_)\n            {\n                it.Value.OnGRContextCreated();\n            }\n        }\n\n        // Called from GPU thread.\n        public void OnGRContextDestroyed()\n        {\n            foreach (var it in mapping_)\n            {\n                it.Value.OnGRContextDestroyed();\n            }\n        }\n\n        private SortedDictionary<ulong, Texture> mapping_ = new SortedDictionary<ulong, Texture>();\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/FlutterBinding.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"Minikin\\Arrays.cs\" />\n    <Compile Remove=\"Minikin\\CmapCoverage.cs\" />\n    <Compile Remove=\"Minikin\\CmapCoverage.h.cs\" />\n    <Compile Remove=\"Minikin\\DefineConstants.cs\" />\n    <Compile Remove=\"Minikin\\Emoji.cs\" />\n    <Compile Remove=\"Minikin\\Emoji.h.cs\" />\n    <Compile Remove=\"Minikin\\FontCollection.cs\" />\n    <Compile Remove=\"Minikin\\FontCollection.h.cs\" />\n    <Compile Remove=\"Minikin\\FontFamily.cs\" />\n    <Compile Remove=\"Minikin\\FontFamily.h.cs\" />\n    <Compile Remove=\"Minikin\\FontLanguage.cs\" />\n    <Compile Remove=\"Minikin\\FontLanguageListCache.cs\" />\n    <Compile Remove=\"Minikin\\FontUtils.cs\" />\n    <Compile Remove=\"Minikin\\GlobalMembers.cs\" />\n    <Compile Remove=\"Minikin\\GraphemeBreak.cs\" />\n    <Compile Remove=\"Minikin\\GraphemeBreak.h.cs\" />\n    <Compile Remove=\"Minikin\\HbFontCache.cs\" />\n    <Compile Remove=\"Minikin\\Hyphenator.cs\" />\n    <Compile Remove=\"Minikin\\Layout.cs\" />\n    <Compile Remove=\"Minikin\\Layout.h.cs\" />\n    <Compile Remove=\"Minikin\\LayoutUtils.cs\" />\n    <Compile Remove=\"Minikin\\LineBreaker.cs\" />\n    <Compile Remove=\"Minikin\\LineBreaker.h.cs\" />\n    <Compile Remove=\"Minikin\\Measurement.cs\" />\n    <Compile Remove=\"Minikin\\Measurement.h.cs\" />\n    <Compile Remove=\"Minikin\\minikin.android.cs\" />\n    <Compile Remove=\"Minikin\\minikin.Hyphenator.cs\" />\n    <Compile Remove=\"Minikin\\minikin.SparseBitSet.cs\" />\n    <Compile Remove=\"Minikin\\MinikinFont.cs\" />\n    <Compile Remove=\"Minikin\\MinikinFont.h.cs\" />\n    <Compile Remove=\"Minikin\\MinikinInternal.cs\" />\n    <Compile Remove=\"Minikin\\SparseBitSet.cs\" />\n    <Compile Remove=\"Minikin\\SparseBitSet.h.cs\" />\n    <Compile Remove=\"Minikin\\StringFunctions.cs\" />\n    <Compile Remove=\"Minikin\\WordBreaker.cs\" />\n    <Compile Remove=\"Minikin\\WordBreaker.h.cs\" />\n    <Compile Remove=\"Txt\\asset_font_manager.cs\" />\n    <Compile Remove=\"Txt\\DefineConstants.cs\" />\n    <Compile Remove=\"Txt\\font_asset_provider.cs\" />\n    <Compile Remove=\"Txt\\font_collection.cs\" />\n    <Compile Remove=\"Txt\\font_skia.cs\" />\n    <Compile Remove=\"Txt\\font_style.cs\" />\n    <Compile Remove=\"Txt\\font_weight.cs\" />\n    <Compile Remove=\"Txt\\GlobalMembers.cs\" />\n    <Compile Remove=\"Txt\\paint_record.cs\" />\n    <Compile Remove=\"Txt\\paragraph.cs\" />\n    <Compile Remove=\"Txt\\paragraph_builder.cs\" />\n    <Compile Remove=\"Txt\\paragraph_style.cs\" />\n    <Compile Remove=\"Txt\\platform.cs\" />\n    <Compile Remove=\"Txt\\platform_android.cs\" />\n    <Compile Remove=\"Txt\\SkTextBlob.cs\" />\n    <Compile Remove=\"Txt\\styled_runs.cs\" />\n    <Compile Remove=\"Txt\\text_baseline.cs\" />\n    <Compile Remove=\"Txt\\text_decoration.cs\" />\n    <Compile Remove=\"Txt\\text_shadow.cs\" />\n    <Compile Remove=\"Txt\\text_style.cs\" />\n    <Compile Remove=\"Txt\\typeface_font_asset_provider.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n    <PackageReference Include=\"SkiaSharp\" Version=\"1.60.3\" />\n    <PackageReference Include=\"SkiaSharp.Extended\" Version=\"1.60.0\" />\n    <PackageReference Include=\"SkiaSharp.HarfBuzz\" Version=\"1.60.3\" />\n    <PackageReference Include=\"SkiaSharp.Svg\" Version=\"1.60.0\" />\n    <PackageReference Include=\"SkiaSharp.Views\" Version=\"1.60.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Minikin\\\" />\n    <Folder Include=\"Txt\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Minikin\\\" />\n    <Folder Include=\"Txt\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "FlutterBinding/Mapping/Future.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace FlutterBinding.Mapping\n{\n    public class Future<T> : Task<T>\n    {\n        public Future(Func<T> function) : base(function) { }\n    }\n\n\n    public class Future : Task\n    {\n        public Future(Action action) : base(action) { }\n    }\n\n}"
  },
  {
    "path": "FlutterBinding/Mapping/Helper.cs",
    "content": "﻿using FlutterBinding.UI;\nusing System;\nusing System.Collections.Generic;\n\nnamespace FlutterBinding.Mapping\n{\n    public static class Helper\n    {\n        public static bool identical(object first, object second) => first.Equals(second);\n\n        public static int hashValues(object first, object second, object third = null, object fourth = null, object fifth = null, object sixth = null, object seventh = null, object eigth = null, object ninth = null) => 0; // TODO:\n\n        public static int hashList(List<double> list) => 0; // TODO:\n        public static int hashList(List<int> list) => 0; // TODO:\n\n        public static string toStringAsFixed(this double value, int points)\n        {\n            return value.ToString($\"N{points}\");\n        }\n\n        public static string toRadixString(this uint value, int places) => value.ToString(); // TODO:\n\n        public static double round(this double value) => Math.Round(value);\n\n        public static int toInt(this double value) => Convert.ToInt32(value);\n\n        public static int clamp(this int value, int lower, int upper)\n        {\n            if (value > upper)\n                return upper;\n\n            if (value < lower)\n                return lower;\n\n            return value;\n        }\n\n        public static double clamp(this double value, int lower, int upper)\n        {\n            if (value > upper)\n                return upper;\n\n            if (value < lower)\n                return lower;\n\n            return value;\n        }\n\n        public static bool isFinite(this double value) => !double.IsInfinity(value);\n\n        public static double abs(this double value) => Math.Abs(value);\n        \n        public static Future<T> _futurize<T>(Action<_Callback<T>> callback)\n        {\n            // Question, why is this so complicated for running a new Task.\n            // Could be a Dart -> C# translation issue\n\n            var result = default(T);\n\n            var resolve = new _Callback<T>((t) => { result = t; });\n\n            return new Future<T>(() => { return result; });\n        }\n\n        public static Future _futurize(Action<_Callback> callback)\n        {\n            // Question, why is this so complicated for running a new Task.\n            // Could be a Dart -> C# translation issue\n\n            var resolve = new _Callback(()=> { });\n\n            return new Future(() => {  });\n        }\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Mapping/Types.cs",
    "content": "﻿using FlutterBinding.UI;\nusing System;\nusing System.Collections.Generic;\n\nnamespace FlutterBinding.Mapping\n{\n    public static class Types\n    {\n        public enum Endian\n        {\n            Big,\n            Little\n        }\n        \n        public class Duration\n        {\n            public Duration(long milliseconds = 0, long microseconds = 0)\n            {\n\n            }\n\n            public static Duration zero = new Duration(); //TODO: make an actual zero\n        }\n\n        public class ByteData\n        {\n            public ByteData() { }\n            public ByteData(int value) { }\n\n            public int getInt32(int first, int second) => 0; // TODO:\n            public int getInt64(int first, int second) => 0; // TODO:\n            public double getFloat64(int first, int second) => 0; // TODO:\n            public double getFloat32(int first, int second) => 0; // TODO:\n\n            public void setInt32(int first, int second, int third) { }\n            public void setFloat32(double first, double second, int third) { }\n\n            public int lengthInBytes => 0; // TODO;\n\n            public static ByteData asByteData(List<int> list) => new ByteData(); // TODO:\n        }\n\n        public class Zone\n        {\n            public static Zone current = new Zone();\n            public void runUnaryGuarded(PlatformMessageResponseCallback callback, ByteData data)\n            {\n                // TODO:\n            }\n\n            public void runUnaryGuarded<A>(Action<A> callback, A data)\n            {\n                // TODO:\n            }\n\n            public void runGuarded(VoidCallback callback)\n            {\n                // TODO:\n            }\n\n            public void runBinaryGuarded<A1, A2>(Action<A1, A2> callback, A1 arg1, A2 arg2)\n            {\n                // TODO:\n            }\n        }\n\n        public class StateError : Exception {\n            public StateError(string message) : base(message) { }\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Minikin/Arrays.cs",
    "content": "﻿//----------------------------------------------------------------------------------------\n//\tCopyright © 2006 - 2018 Tangible Software Solutions, Inc.\n//\tThis class can be used by anyone provided that the copyright notice remains intact.\n//\n//\tThis class provides the ability to initialize and delete array elements.\n//----------------------------------------------------------------------------------------\ninternal static class Arrays\n{\n\tpublic static T[] InitializeWithDefaultInstances<T>(int length) where T : new()\n\t{\n\t\tT[] array = new T[length];\n\t\tfor (int i = 0; i < length; i++)\n\t\t{\n\t\t\tarray[i] = new T();\n\t\t}\n\t\treturn array;\n\t}\n\n\tpublic static void DeleteArray<T>(T[] array) where T: System.IDisposable\n\t{\n\t\tforeach (T element in array)\n\t\t{\n\t\t\tif (element != null)\n\t\t\t\telement.Dispose();\n\t\t}\n\t}\n}"
  },
  {
    "path": "FlutterBinding/Minikin/CmapCoverage.cs",
    "content": "﻿/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Determine coverage of font given its raw \"cmap\" OpenType table\n\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/CmapCoverage.h.cs",
    "content": "﻿/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\nnamespace minikin\n{\n\n    public class CmapCoverage\n    {\n        public SparseBitSet getCoverage(byte cmap_data, int cmap_size, ref bool has_cmap_format14_subtable)\n        {\n            const int kHeaderSize = 4;\n            const int kNumTablesOffset = 2;\n            const int kTableSize = 8;\n            const int kPlatformIdOffset = 0;\n            const int kEncodingIdOffset = 2;\n            const int kOffsetOffset = 4;\n            const int kFormatOffset = 0;\n            const uint kInvalidOffset = UINT32_MAX;\n\n            if (kHeaderSize > cmap_size)\n            {\n                return SparseBitSet();\n            }\n            uint numTables = readU16(cmap_data, kNumTablesOffset);\n            if (kHeaderSize + numTables * kTableSize > cmap_size != null)\n            {\n                return SparseBitSet();\n            }\n\n            uint bestTableOffset = new uint(kInvalidOffset);\n            UInt16 bestTableFormat = 0;\n            byte bestTablePriority = kLowestPriority;\n            has_cmap_format14_subtable = false;\n            for (uint i = 0; i < numTables; ++i)\n            {\n                uint tableHeadOffset = kHeaderSize + i * kTableSize;\n                UInt16 platformId = readU16(cmap_data, tableHeadOffset + kPlatformIdOffset);\n                UInt16 encodingId = readU16(cmap_data, tableHeadOffset + kEncodingIdOffset);\n                uint offset = readU32(cmap_data, tableHeadOffset + kOffsetOffset);\n\n                if (offset > cmap_size - 2)\n                {\n                    continue; // Invalid table: not enough space to read.\n                }\n                UInt16 format = readU16(cmap_data, offset + kFormatOffset);\n\n                if (platformId == 0 && encodingId == 5)\n                {\n                    if (!has_cmap_format14_subtable && format == 14)\n                    {\n                        has_cmap_format14_subtable = true;\n                    }\n                    else\n                    {\n                        // Ignore the (0, 5) table if we have already seen another valid one or\n                        // it's in a format we don't understand.\n                    }\n                }\n                else\n                {\n                    uint length = new uint();\n                    uint language = new uint();\n\n                    if (format == 4)\n                    {\n                        const int lengthOffset = 2;\n                        const int languageOffset = 4;\n                        const int minTableSize = languageOffset + 2;\n                        if (offset > cmap_size - minTableSize)\n                        {\n                            continue; // Invalid table: not enough space to read.\n                        }\n                        length = readU16(cmap_data, offset + lengthOffset);\n                        language = readU16(cmap_data, offset + languageOffset);\n                    }\n                    else if (format == 12)\n                    {\n                        const int lengthOffset = 4;\n                        const int languageOffset = 8;\n                        const int minTableSize = languageOffset + 4;\n                        if (offset > cmap_size - minTableSize)\n                        {\n                            continue; // Invalid table: not enough space to read.\n                        }\n                        length = readU32(cmap_data, offset + lengthOffset);\n                        language = readU32(cmap_data, offset + languageOffset);\n                    }\n                    else\n                    {\n                        continue;\n                    }\n\n                    if (length > cmap_size - offset)\n                    {\n                        continue; // Invalid table: table length is larger than whole cmap data\n                                  // size.\n                    }\n                    if (language != 0)\n                    {\n                        // Unsupported or invalid table: this is either a subtable for the\n                        // Macintosh platform (which we don't support), or an invalid subtable\n                        // since language field should be zero for non-Macintosh subtables.\n                        continue;\n                    }\n                    byte priority = getTablePriority(new UInt16(platformId), new UInt16(encodingId));\n                    if (priority < bestTablePriority)\n                    {\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: bestTableOffset = offset;\n                        bestTableOffset.CopyFrom(offset);\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: bestTablePriority = priority;\n                        bestTablePriority.CopyFrom(priority);\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: bestTableFormat = format;\n                        bestTableFormat.CopyFrom(format);\n                    }\n                }\n                if (has_cmap_format14_subtable && bestTablePriority == 0)\n                {\n                    // Already found the highest priority table and variation sequences table.\n                    // No need to look at remaining tables.\n                    break;\n                }\n            }\n            if (bestTableOffset == kInvalidOffset)\n            {\n                return SparseBitSet();\n            }\n            byte tableData = cmap_data + bestTableOffset;\n            int tableSize = cmap_size - bestTableOffset;\n            vector<uint> coverageVec = new vector<uint>();\n            bool success;\n            if (bestTableFormat == 4)\n            {\n                success = getCoverageFormat4(coverageVec, tableData, tableSize);\n            }\n            else\n            {\n                success = getCoverageFormat12(coverageVec, tableData, tableSize);\n            }\n            if (success && (coverageVec.size() != 0))\n            {\n                return SparseBitSet(coverageVec.front(), coverageVec.size() >> 1);\n            }\n            else\n            {\n                return SparseBitSet();\n            }\n        }\n    }\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/DefineConstants.cs",
    "content": "﻿internal static class DefineConstants\n{\n//C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n\tpublic const string LOG_TAG = \"Minikin\";\n\tpublic const string LOG_TAG = \"SparseBitSet\";\n\tpublic const int U_USING_ICU_NAMESPACE = 0;\n\tpublic const int VERBOSE_DEBUG = 0;\n}"
  },
  {
    "path": "FlutterBinding/Minikin/Emoji.cs",
    "content": "﻿/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/Emoji.h.cs",
    "content": "﻿/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontCollection.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #define VERBOSE_DEBUG\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/unistr.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/unorm2.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/utf16.h\"\n\n\n\nnamespace minikin\n{\n\n//C++ TO C# CONVERTER TODO TASK: The original C++ template specifier was replaced with a C# generic specifier, which may not produce the same behavior:\n//ORIGINAL LINE: template <typename T>\n\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n\n\n// Calculates a font score.\n// The score of the font family is based on three subscores.\n//  - Coverage Score: How well the font family covers the given character or\n//  variation sequence.\n//  - Language Score: How well the font family is appropriate for the language.\n//  - Variant Score: Whether the font family matches the variant. Note that this\n//  variant is not the\n//    one in BCP47. This is our own font variant (e.g., elegant, compact).\n//\n// Then, there is a priority for these three subscores as follow:\n//   Coverage Score > Language Score > Variant Score\n// The returned score reflects this priority order.\n//\n// Note that there are two special scores.\n//  - kUnsupportedFontScore: When the font family doesn't support the variation\n//  sequence or even its\n//    base character.\n//  - kFirstFontScore: When the font is the first font family in the collection\n//  and it supports the\n//    given character or variation sequence.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint FontCollection::calcFamilyScore(uint ch, uint vs, int variant, uint langListId, const FontFamily*& fontFamily) const\n\n// Calculates a font score based on variation sequence coverage.\n// - Returns kUnsupportedFontScore if the font doesn't support the variation\n// sequence or its base\n//   character.\n// - Returns kFirstFontScore if the font family is the first font family in the\n// collection and it\n//   supports the given character or variation sequence.\n// - Returns 3 if the font family supports the variation sequence.\n// - Returns 2 if the vs is a color variation selector (U+FE0F) and if the font\n// is an emoji font.\n// - Returns 2 if the vs is a text variation selector (U+FE0E) and if the font\n// is not an emoji font.\n// - Returns 1 if the variation selector is not specified or if the font family\n// only supports the\n//   variation sequence's base character.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint FontCollection::calcCoverageScore(uint ch, uint vs, const FontFamily*& fontFamily) const\n\n// Calculate font scores based on the script matching, subtag matching and\n// primary langauge matching.\n//\n// 1. If only the font's language matches or there is no matches between\n// requested font and\n//    supported font, then the font obtains a score of 0.\n// 2. Without a match in language, considering subtag may change font's\n// EmojiStyle over script,\n//    a match in subtag gets a score of 2 and a match in scripts gains a score\n//    of 1.\n// 3. Regarding to two elements matchings, language-and-subtag matching has a\n// score of 4, while\n//    language-and-script obtains a socre of 3 with the same reason above.\n//\n// If two languages in the requested list have the same language score, the font\n// matching with higher priority language gets a higher score. For example, in\n// the case the user requested language list is \"ja-Jpan,en-Latn\". The score of\n// for the font of \"ja-Jpan\" gets a higher score than the font of \"en-Latn\".\n//\n// To achieve score calculation with priorities, the language score is\n// determined as follows:\n//   LanguageScore = s(0) * 5^(m - 1) + s(1) * 5^(m - 2) + ... + s(m - 2) * 5 +\n//   s(m - 1)\n// Here, m is the maximum number of languages to be compared, and s(i) is the\n// i-th language's matching score. The possible values of s(i) are 0, 1, 2, 3\n// and 4.\n\n// Calculates a font score based on variant (\"compact\" or \"elegant\") matching.\n//  - Returns 1 if the font doesn't have variant or the variant matches with the\n//  text style.\n//  - No score if the font has a variant but it doesn't match with the text\n//  style.\n\n// Implement heuristic for choosing best-match font. Here are the rules:\n// 1. If first font in the collection has the character, it wins.\n// 2. Calculate a score for the font family. See comments in calcFamilyScore for\n// the detail.\n// 3. Highest score wins, with ties resolved to the first font.\n// This method never returns nullptr.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const FontFamily*& FontCollection::getFamilyForChar(uint ch, uint vs, uint langListId, int variant) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool FontCollection::hasVariationSelector(uint baseCodepoint, uint variationSelector) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void FontCollection::itemize(const UInt16* string, int string_size, FontStyle style, vector<Run>* result) const\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint FontCollection::getId() const\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontCollection.h.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\nnamespace minikin\n{\n\n    public class FontCollection\n    {\n        public FontCollection(FontFamily typeface)\n        {\n            this.mMaxChar = 0;\n            List<FontFamily> typefaces = new List<FontFamily>();\n            typefaces.Add(typeface);\n            init(typefaces);\n        }\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public FontCollection(vector<FontFamily> typefaces)\n        {\n            this.mMaxChar = 0;\n            init(typefaces);\n        }\n\n        // libtxt extension: an interface for looking up fallback fonts for characters\n        // that do not match this collection's font families.\n        public abstract class FallbackFontProvider //: System.IDisposable\n        {\n            //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n            //\tvirtual ~FallbackFontProvider() = default;\n            public abstract FontFamily* matchFallbackFont(uint ch, string locale);\n        }\n\n        public class Run\n        {\n            public FakedFont fakedFont = new FakedFont();\n            public int start;\n            public int end;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: void itemize(const UInt16* string, int string_length, FontStyle style, ClassicVector<Run>* result) const;\n        public void itemize(UInt16 @string, int string_size, FontStyle style, vector<Run> result)\n        {\n            uint langListId = style.getLanguageListId();\n            int variant = style.getVariant();\n            FontFamily lastFamily = null;\n            Run run = null;\n\n            if (string_size == 0)\n            {\n                return;\n            }\n\n            const uint kEndOfString = 0xFFFFFFFF;\n\n            uint nextCh = 0;\n            uint prevCh = 0;\n            int nextUtf16Pos = 0;\n            int readLength = 0;\n            U16_NEXT(@string, readLength, string_size, nextCh);\n\n            do\n            {\n                uint ch = new uint(nextCh);\n                int utf16Pos = nextUtf16Pos;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: nextUtf16Pos = readLength;\n                nextUtf16Pos.CopyFrom(readLength);\n                if (readLength < string_size)\n                {\n                    U16_NEXT(@string, readLength, string_size, nextCh);\n                }\n                else\n                {\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: nextCh = kEndOfString;\n                    nextCh = kEndOfString;\n                }\n\n                bool shouldContinueRun = false;\n                if (lastFamily != null)\n                {\n                    if (isStickyWhitelisted(ch))\n                    {\n                        // Continue using existing font as long as it has coverage and is\n                        // whitelisted\n                        shouldContinueRun = lastFamily.getCoverage().get(ch);\n                    }\n                    else if (ch == SOFT_HYPHEN || isVariationSelector(ch))\n                    {\n                        // Always continue if the character is the soft hyphen or a variation\n                        // selector.\n                        shouldContinueRun = true;\n                    }\n                }\n\n                if (!shouldContinueRun)\n                {\n                    FontFamily* family = getFamilyForChar(ch, isVariationSelector(new uint(nextCh)) ? nextCh : 0, langListId, variant);\n                    if (utf16Pos == 0 || family.get() != lastFamily)\n                    {\n                        int start = utf16Pos;\n                        // Workaround for combining marks and emoji modifiers until we implement\n                        // per-cluster font selection: if a combining mark or an emoji modifier\n                        // is found in a different font that also supports the previous\n                        // character, attach previous character to the new run. U+20E3 COMBINING\n                        // ENCLOSING KEYCAP, used in emoji, is handled properly by this since\n                        // it's a combining mark too.\n                        if (utf16Pos != 0 && ((U_GET_GC_MASK(ch) & U_GC_M_MASK) != 0 || (isEmojiModifier(ch) && isEmojiBase(prevCh))) && family != null && family.getCoverage().get(prevCh))\n                        {\n                            int prevChLength = U16_LENGTH(prevCh);\n                            run.end -= prevChLength;\n                            if (run.start == run.end)\n                            {\n                                result.pop_back();\n                            }\n                            start -= prevChLength;\n                        }\n                        result.push_back({ family.getClosestMatch(style), (int)start, 0});\n                        run = result.back();\n                        lastFamily = family.get();\n                    }\n                }\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: prevCh = ch;\n                prevCh.CopyFrom(ch);\n                run.end = nextUtf16Pos; // exclusive\n            } while (nextCh != kEndOfString);\n        }\n\n        // Returns true if there is a glyph for the code point and variation selector\n        // pair. Returns false if no fonts have a glyph for the code point and\n        // variation selector pair, or invalid variation selector is passed.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool hasVariationSelector(uint baseCodepoint, uint variationSelector) const;\n        public bool hasVariationSelector(uint baseCodepoint, uint variationSelector)\n        {\n            if (!isVariationSelector(new uint(variationSelector)))\n            {\n                return false;\n            }\n            if (baseCodepoint >= mMaxChar)\n            {\n                return false;\n            }\n\n            std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n\n            // Currently mRanges can not be used here since it isn't aware of the\n            // variation sequence.\n            for (int i = 0; i < mVSFamilyVec.size(); i++)\n            {\n                if (mVSFamilyVec[i].hasGlyph(baseCodepoint, variationSelector))\n                {\n                    return true;\n                }\n            }\n\n            // Even if there is no cmap format 14 subtable entry for the given sequence,\n            // should return true for <char, text presentation selector> case since we\n            // have special fallback rule for the sequence. Note that we don't need to\n            // restrict this to already standardized variation sequences, since Unicode is\n            // adding variation sequences more frequently now and may even move towards\n            // allowing text and emoji variation selectors on any character.\n            if (variationSelector == TEXT_STYLE_VS)\n            {\n                for (int i = 0; i < mFamilies.size(); ++i)\n                {\n                    if (!mFamilies[i].isColorEmojiFamily() && mFamilies[i].hasGlyph(baseCodepoint, 0))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        // Get base font with fakery information (fake bold could affect metrics)\n        public FakedFont baseFontFaked(FontStyle style)\n        {\n            return mFamilies[0].getClosestMatch(style);\n        }\n\n        // Creates new FontCollection based on this collection while applying font\n        // variations. Returns nullptr if none of variations apply to this collection.\n        public FontCollection createCollectionWithVariation(List<FontVariation> variations)\n        {\n            if (variations.Count == 0 || mSupportedAxes.empty())\n            {\n                return null;\n            }\n\n            bool hasSupportedAxis = false;\n            foreach (FontVariation variation in variations)\n            {\n                if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end())\n                {\n                    hasSupportedAxis = true;\n                    break;\n                }\n            }\n            if (!hasSupportedAxis)\n            {\n                // None of variation axes are supported by this font collection.\n                return null;\n            }\n\n            List<FontFamily> families = new List<FontFamily>();\n            foreach (FontFamily family in mFamilies)\n            {\n                FontFamily newFamily = family.createFamilyWithVariation(variations);\n                if (newFamily != null)\n                {\n                    families.Add(newFamily);\n                }\n                else\n                {\n                    families.Add(family);\n                }\n            }\n\n            return new FontCollection(families);\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const ClassicUnorderedSet<AxisTag>& getSupportedTags() const\n        public HashSet<AxisTag> getSupportedTags()\n        {\n            return mSupportedAxes;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: uint getId() const;\n        public uint getId()\n        {\n            return mId;\n        }\n\n        public void set_fallback_font_provider(std::unique_ptr<FallbackFontProvider> ffp)\n        {\n            mFallbackFontProvider = std::move(ffp);\n        }\n\n        private const int kLogCharsPerPage = 8;\n        private int kPageMask = (1 << kLogCharsPerPage) - 1;\n\n        // mFamilyVec holds the indices of the mFamilies and mRanges holds the range\n        // of indices of mFamilyVec. The maximum number of pages is 0x10FF (U+10FFFF\n        // >> 8). The maximum number of the fonts is 0xFF. Thus, technically the\n        // maximum length of mFamilyVec is 0x10EE01 (0x10FF * 0xFF). However, in\n        // practice, 16-bit integers are enough since most fonts supports only limited\n        // range of code points.\n        private class Range\n        {\n            public UInt16 start = new UInt16();\n            public UInt16 end = new UInt16();\n        }\n\n        // Initialize the FontCollection.\n        public void init(vector<FontFamily> typefaces)\n        {\n            std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n            mId = GlobalMembers.sNextId++;\n            vector<uint> lastChar = new vector<uint>();\n            int nTypefaces = typefaces.size();\n#if VERBOSE_DEBUG\n\t  ALOGD(\"nTypefaces = %zd\\n\", nTypefaces);\n#endif\n            FontStyle defaultStyle = new FontStyle();\n            for (int i = 0; i < nTypefaces; i++)\n            {\n                FontFamily* family = typefaces[i];\n                if (family.getClosestMatch(defaultStyle).font == null)\n                {\n                    continue;\n                }\n                SparseBitSet coverage = family.getCoverage();\n                mFamilies.push_back(family); // emplace_back would be better\n                if (family.hasVSTable())\n                {\n                    mVSFamilyVec.push_back(family);\n                }\n                mMaxChar = Math.Max(mMaxChar, coverage.length());\n                lastChar.push_back(coverage.nextSetBit(0));\n\n                HashSet<AxisTag> supportedAxes = family.supportedAxes();\n                mSupportedAxes.insert(supportedAxes.GetEnumerator(), supportedAxes.end());\n            }\n            nTypefaces = mFamilies.size();\n            LOG_ALWAYS_FATAL_IF(nTypefaces == 0, \"Font collection must have at least one valid typeface\");\n            LOG_ALWAYS_FATAL_IF(nTypefaces > 254, \"Font collection may only have up to 254 font families.\");\n            int nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage;\n            // TODO: Use variation selector map for mRanges construction.\n            // A font can have a glyph for a base code point and variation selector pair\n            // but no glyph for the base code point without variation selector. The family\n            // won't be listed in the range in this case.\n            for (int i = 0; i < nPages; i++)\n            {\n                Range dummy = new Range();\n                mRanges.push_back(dummy);\n                Range range = mRanges.back();\n#if VERBOSE_DEBUG\n\t\tALOGD(\"i=%zd: range start = %zd\\n\", i, offset);\n#endif\n                range.start = mFamilyVec.size();\n                for (int j = 0; j < nTypefaces; j++)\n                {\n                    if (lastChar[j] < (i + 1) << kLogCharsPerPage)\n                    {\n                        FontFamily* family = mFamilies[j];\n                        mFamilyVec.push_back((byte)j);\n                        uint nextChar = family.getCoverage().nextSetBit((i + 1) << kLogCharsPerPage);\n#if VERBOSE_DEBUG\n\t\t\tALOGD(\"nextChar = %d (j = %zd)\\n\", nextChar, j);\n#endif\n                        lastChar[j] = nextChar;\n                    }\n                }\n                range.end = mFamilyVec.size();\n            }\n            // See the comment in Range for more details.\n            LOG_ALWAYS_FATAL_IF(mFamilyVec.size() >= 0xFFFF, \"Exceeded the maximum indexable cmap coverage.\");\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const FontFamily*& getFamilyForChar(uint ch, uint vs, uint langListId, int variant) const;\n        public FontFamily* getFamilyForChar(uint ch, uint vs, uint langListId, int variant)\n        {\n            if (ch >= mMaxChar)\n            {\n                // libtxt: check if the fallback font provider can match this character\n                if (mFallbackFontProvider)\n                {\n                    FontFamily* fallback = mFallbackFontProvider.matchFallbackFont(ch, GetFontLocale(new uint(langListId)));\n                    if (fallback != null)\n                    {\n                        return fallback;\n                    }\n                }\n                return mFamilies[0];\n            }\n\n            Range range = mRanges[ch >> kLogCharsPerPage];\n\n            if (vs != 0)\n            {\n                range = new Range(0, (UInt16)mFamilies.size());\n            }\n\n#if VERBOSE_DEBUG\n\t  ALOGD(\"querying range %zd:%zd\\n\", range.start, range.end);\n#endif\n            int bestFamilyIndex = -1;\n            uint bestScore = kUnsupportedFontScore;\n            for (int i = range.start; i < range.end; i++)\n            {\n                FontFamily* family = vs == 0 ? mFamilies[mFamilyVec[i]] : mFamilies[i];\n                uint score = calcFamilyScore(ch, vs, variant, langListId, family);\n                if (score == kFirstFontScore)\n                {\n                    // If the first font family supports the given character or variation\n                    // sequence, always use it.\n                    return family;\n                }\n                if (score > bestScore)\n                {\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: bestScore = score;\n                    bestScore.CopyFrom(score);\n                    bestFamilyIndex = i;\n                }\n            }\n            if (bestFamilyIndex == -1)\n            {\n                // libtxt: check if the fallback font provider can match this character\n                if (mFallbackFontProvider)\n                {\n                    FontFamily* fallback = mFallbackFontProvider.matchFallbackFont(ch, GetFontLocale(new uint(langListId)));\n                    if (fallback != null)\n                    {\n                        return fallback;\n                    }\n                }\n\n                UErrorCode errorCode = U_ZERO_ERROR;\n                UNormalizer2 normalizer = unorm2_getNFDInstance(errorCode);\n                if (U_SUCCESS(errorCode))\n                {\n                    UChar[] decomposed = Arrays.InitializeWithDefaultInstances<UChar>(4);\n                    int len = unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, errorCode);\n                    if (U_SUCCESS(errorCode) && len > 0)\n                    {\n                        int off = 0;\n                        U16_NEXT_UNSAFE(decomposed, off, ch);\n                        return getFamilyForChar(ch, vs, langListId, variant);\n                    }\n                }\n                return mFamilies[0];\n            }\n            return vs == 0 ? mFamilies[mFamilyVec[bestFamilyIndex]] : mFamilies[bestFamilyIndex];\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: uint calcFamilyScore(uint ch, uint vs, int variant, uint langListId, const FontFamily*& fontFamily) const;\n        public uint calcFamilyScore(uint ch, uint vs, int variant, uint langListId, FontFamily fontFamily)\n        {\n            uint coverageScore = calcCoverageScore(ch, vs, fontFamily);\n            if (coverageScore == kFirstFontScore || coverageScore == kUnsupportedFontScore)\n            {\n                // No need to calculate other scores.\n                return coverageScore;\n            }\n\n            uint languageScore = calcLanguageMatchingScore(langListId, fontFamily);\n            uint variantScore = calcVariantMatchingScore(variant, fontFamily);\n\n            // Subscores are encoded into 31 bits representation to meet the subscore\n            // priority. The highest 2 bits are for coverage score, then following 28 bits\n            // are for language score, then the last 1 bit is for variant score.\n            return coverageScore << 29 | languageScore << 1 | variantScore;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: uint calcCoverageScore(uint ch, uint vs, const FontFamily*& fontFamily) const;\n        public uint calcCoverageScore(uint ch, uint vs, FontFamily fontFamily)\n        {\n            bool hasVSGlyph = (vs != 0) && fontFamily.hasGlyph(ch, vs);\n            if (!hasVSGlyph && !fontFamily.getCoverage().get(ch))\n            {\n                // The font doesn't support either variation sequence or even the base\n                // character.\n                return kUnsupportedFontScore;\n            }\n\n            if ((vs == 0 || hasVSGlyph) && mFamilies[0] == fontFamily)\n            {\n                // If the first font family supports the given character or variation\n                // sequence, always use it.\n                return kFirstFontScore;\n            }\n\n            if (vs == 0)\n            {\n                return 1;\n            }\n\n            if (hasVSGlyph)\n            {\n                return 3;\n            }\n\n            if (vs == EMOJI_STYLE_VS || vs == TEXT_STYLE_VS)\n            {\n                FontLanguages langs = FontLanguageListCache.getById(fontFamily.langId());\n                bool hasEmojiFlag = false;\n                for (int i = 0; i < langs.size(); ++i)\n                {\n                    if (langs[i].getEmojiStyle() == FontLanguage.EMSTYLE_EMOJI)\n                    {\n                        hasEmojiFlag = true;\n                        break;\n                    }\n                }\n\n                if (vs == EMOJI_STYLE_VS)\n                {\n                    return hasEmojiFlag ? 2 : 1;\n                }\n                else\n                { // vs == TEXT_STYLE_VS\n                    return hasEmojiFlag ? 1 : 2;\n                }\n            }\n            return 1;\n        }\n\n        public uint calcLanguageMatchingScore(uint userLangListId, FontFamily fontFamily)\n        {\n            FontLanguages langList = FontLanguageListCache.getById(new uint(userLangListId));\n            FontLanguages fontLanguages = FontLanguageListCache.getById(fontFamily.langId());\n\n            int maxCompareNum = Math.Min(langList.size(), FONT_LANGUAGES_LIMIT);\n            uint score = 0;\n            for (int i = 0; i < maxCompareNum; ++i)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: score = score * 5u + langList[i].calcScoreFor(fontLanguages);\n                score.CopyFrom(score * 5u + langList[i].calcScoreFor(fontLanguages));\n            }\n            return score;\n        }\n\n        public uint calcVariantMatchingScore(int variant, FontFamily fontFamily)\n        {\n            return (fontFamily.variant() == 0 || fontFamily.variant() == variant) ? 1 : 0;\n        }\n\n        // static for allocating unique id's\n        private static uint sNextId = new uint();\n\n        // unique id for this font collection (suitable for cache key)\n        private uint mId = new uint();\n\n        // Highest UTF-32 code point that can be mapped\n        private uint mMaxChar = new uint();\n\n        // This vector has pointers to the all font family instances in this\n        // collection. This vector can't be empty.\n        private List<FontFamily> mFamilies = new List<FontFamily>();\n\n        // Following two vectors are pre-calculated tables for resolving coverage\n        // faster. For example, to iterate over all fonts which support Unicode code\n        // point U+XXYYZZ, iterate font families index from\n        // mFamilyVec[mRanges[0xXXYY].start] to mFamilyVec[mRange[0xXXYY].end] instead\n        // of whole mFamilies. This vector contains indices into mFamilies. This\n        // vector can't be empty.\n        private List<Range> mRanges = new List<Range>();\n        private List<byte> mFamilyVec = new List<byte>();\n\n        // This vector has pointers to the font family instances which have cmap 14\n        // subtables.\n        private List<FontFamily> mVSFamilyVec = new List<FontFamily>();\n\n        // Set of supported axes in this collection.\n        private HashSet<AxisTag> mSupportedAxes = new HashSet<AxisTag>();\n\n        // libtxt extension: Fallback font provider.\n        private std::unique_ptr<FallbackFontProvider> mFallbackFontProvider = new std::unique_ptr<FallbackFontProvider>();\n    }\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontFamily.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n\n\nnamespace minikin\n{\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: android::hash_t FontStyle::hash() const\n\n// static\n\n// static\n\n\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: ClassicUnorderedSet<AxisTag> Font::getSupportedAxesLocked() const\n\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n\n// static\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: FakedFont FontFamily::getClosestMatch(FontStyle style) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool FontFamily::isColorEmojiFamily() const\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool FontFamily::hasGlyph(uint codepoint, uint variationSelector) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: FontFamily FontFamily::createFamilyWithVariation(const ClassicVector<FontVariation>& variations) const\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontFamily.h.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n\nnamespace minikin\n{\n\n    //C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n    //class MinikinFont;\n\n    // FontStyle represents all style information needed to select an actual font\n    // from a collection. The implementation is packed into two 32-bit words\n    // so it can be efficiently copied, embedded in other objects, etc.\n    public class FontStyle\n    {\n        public FontStyle() : this(0, 4, false)\n        {\n        }\n        public FontStyle(int weight, bool italic) : this(0, weight, italic)\n        {\n        }\n        public FontStyle(uint langListId) : this(new uint(langListId), 0, 4, false)\n        {\n        }\n\n        public FontStyle(int variant, int weight, bool italic)\n        {\n             FontStyle(FontLanguageListCache.kEmptyListId, variant, weight, italic);\n        }\n        public FontStyle(uint languageListId, int variant, int weight, bool italic)\n        {\n            this.bits = pack(variant, weight, italic);\n            this.mLanguageListId = languageListId;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int getWeight() const\n        public int getWeight()\n        {\n            return bits & kWeightMask;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool getItalic() const\n        public bool getItalic()\n        {\n            return (bits & kItalicMask) != 0;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int getVariant() const\n        public int getVariant()\n        {\n            return (bits >> kVariantShift) & kVariantMask;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: uint getLanguageListId() const\n        public uint getLanguageListId()\n        {\n            return mLanguageListId;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool operator ==(const FontStyle other) const\n        public static bool operator ==(FontStyle ImpliedObject, FontStyle other)\n        {\n            return ImpliedObject.bits == other.bits && ImpliedObject.mLanguageListId == other.mLanguageListId;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: android::hash_t hash() const;\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  android::hash_t hash();\n\n        // Looks up a language list from an internal cache and returns its ID.\n        // If the passed language list is not in the cache, registers it and returns\n        // newly assigned ID.\n        public uint registerLanguageList(string languages)\n        {\n            std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n            return FontLanguageListCache.getId(languages);\n        }\n\n        private uint kWeightMask = (1 << 4) - 1;\n        private uint kItalicMask = 1 << 4;\n        private const int kVariantShift = 5;\n        private uint kVariantMask = (1 << 2) - 1;\n\n        public uint pack(int variant, int weight, bool italic)\n        {\n            return (weight & kWeightMask) | (italic ? kItalicMask : 0) | (variant << kVariantShift);\n        }\n\n        private uint bits = new uint();\n        private uint mLanguageListId = new uint();\n    }\n\n    public enum FontVariant\n    {\n        VARIANT_DEFAULT = 0,\n        VARIANT_COMPACT = 1,\n        VARIANT_ELEGANT = 2,\n    }\n\n    // attributes representing transforms (fake bold, fake italic) to match styles\n    public class FontFakery\n    {\n        public FontFakery()\n        {\n            this.mFakeBold = false;\n            this.mFakeItalic = false;\n        }\n        public FontFakery(bool fakeBold, bool fakeItalic)\n        {\n            this.mFakeBold = fakeBold;\n            this.mFakeItalic = fakeItalic;\n        }\n        // TODO: want to support graded fake bolding\n        public bool isFakeBold()\n        {\n            return mFakeBold;\n        }\n        public bool isFakeItalic()\n        {\n            return mFakeItalic;\n        }\n\n        private bool mFakeBold;\n        private bool mFakeItalic;\n    }\n\n    public class FakedFont\n    {\n        // ownership is the enclosing FontCollection\n        public MinikinFont font;\n        public FontFakery fakery = new FontFakery();\n    }\n\n\n    public class Font\n    {\n        public Font(MinikinFont typeface, FontStyle style)\n        {\n            this.typeface = typeface;\n            this.style = style;\n        }\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public Font(MinikinFont typeface, FontStyle style)\n        {\n            this.typeface = typeface;\n            this.style = style;\n        }\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public Font(Font o)\n        {\n            typeface = std::move(o.typeface);\n            style = o.style;\n            o.typeface = null;\n        }\n        public Font(Font o)\n        {\n            typeface = o.typeface;\n            style = o.style;\n        }\n\n        public MinikinFont typeface;\n        public FontStyle style = new FontStyle();\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: ClassicUnorderedSet<AxisTag> getSupportedAxesLocked() const;\n        public HashSet<AxisTag> getSupportedAxesLocked()\n        {\n            uint fvarTag = MinikinFont.MakeTag('f', 'v', 'a', 'r');\n            HbBlob fvarTable = new HbBlob(getFontTable(typeface.get(), new uint(fvarTag)));\n            if (fvarTable.size() == 0)\n            {\n                return new HashSet<AxisTag>();\n            }\n\n            HashSet<AxisTag> supportedAxes = new HashSet<AxisTag>();\n            analyzeAxes(fvarTable.get(), fvarTable.size(), supportedAxes);\n            return supportedAxes;\n        }\n    }\n\n    public class FontVariation\n    {\n        public FontVariation(AxisTag axisTag, float value)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.axisTag = axisTag;\n            this.axisTag.CopyFrom(axisTag);\n            this.value = value;\n        }\n        public AxisTag axisTag = new AxisTag();\n        public float value;\n    }\n\n    public class FontFamily\n    {\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public FontFamily(List<Font> fonts)\n        {\n            FontFamily(0, std::move(fonts));\n        }\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public FontFamily(int variant, List<Font> fonts)\n        {\n            FontFamily(FontLanguageListCache.kEmptyListId, variant, std::move(fonts));\n        }\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public FontFamily(uint langId, int variant, List<Font> fonts)\n        {\n            this.mLangId = langId;\n            this.mVariant = variant;\n            this.mFonts = std::move(fonts);\n            this.mHasVSTable = false;\n            computeCoverage();\n        }\n\n        // TODO: Good to expose FontUtil.h.\n        public bool analyzeStyle(MinikinFont typeface, ref int weight, ref bool italic)\n        {\n            std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n            uint os2Tag = MinikinFont.MakeTag('O', 'S', '/', '2');\n            HbBlob os2Table = new HbBlob(getFontTable(typeface.get(), new uint(os2Tag)));\n            if (os2Table.get() == null)\n            {\n                return false;\n            }\n            return global::minikin.analyzeStyle(os2Table.get(), os2Table.size(), weight, italic);\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: FakedFont getClosestMatch(FontStyle style) const;\n        public FakedFont getClosestMatch(FontStyle style)\n        {\n            Font bestFont = null;\n            int bestMatch = 0;\n            for (int i = 0; i < mFonts.size(); i++)\n            {\n                Font font = mFonts[i];\n                int match = computeMatch(font.style, new FontStyle(style));\n                if (i == 0 || match < bestMatch)\n                {\n                    bestFont = font;\n                    bestMatch = match;\n                }\n            }\n            if (bestFont != null)\n            {\n                return new FakedFont() { bestFont.typeface.get(), computeFakery(new FontStyle(style), bestFont.style)};\n            }\n            return new FakedFont() { null, FontFakery()};\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: uint langId() const\n        public uint langId()\n        {\n            return mLangId;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int variant() const\n        public int variant()\n        {\n            return mVariant;\n        }\n\n        // API's for enumerating the fonts in a family. These don't guarantee any\n        // particular order\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int getNumFonts() const\n        public int getNumFonts()\n        {\n            return mFonts.Count;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const MinikinFont*& getFont(int index) const\n        public MinikinFont* getFont(int index)\n        {\n            return mFonts[index].typeface;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: FontStyle getStyle(int index) const\n        public FontStyle getStyle(int index)\n        {\n            return mFonts[index].style;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool isColorEmojiFamily() const;\n        public bool isColorEmojiFamily()\n        {\n            FontLanguages languageList = FontLanguageListCache.getById(mLangId);\n            for (int i = 0; i < languageList.size(); ++i)\n            {\n                if (languageList[i].getEmojiStyle() == FontLanguage.EMSTYLE_EMOJI)\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const ClassicUnorderedSet<AxisTag>& supportedAxes() const\n        public HashSet<AxisTag> supportedAxes()\n        {\n            return mSupportedAxes;\n        }\n\n        // Get Unicode coverage.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const SparseBitSet& getCoverage() const\n        public SparseBitSet getCoverage()\n        {\n            return mCoverage;\n        }\n\n        // Returns true if the font has a glyph for the code point and variation\n        // selector pair. Caller should acquire a lock before calling the method.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool hasGlyph(uint codepoint, uint variationSelector) const;\n        public bool hasGlyph(uint codepoint, uint variationSelector)\n        {\n            assertMinikinLocked();\n            if (variationSelector != 0 && !mHasVSTable)\n            {\n                // Early exit if the variation selector is specified but the font doesn't\n                // have a cmap format 14 subtable.\n                return false;\n            }\n\n            FontStyle defaultStyle = new FontStyle();\n            HarfBuzzSharp.Font font = getHbFontLocked(getClosestMatch(defaultStyle).font);\n            uint unusedGlyph = new uint();\n            bool result = hb_font_get_glyph(font, codepoint, variationSelector, unusedGlyph);\n            hb_font_destroy(font);\n            return result;\n        }\n\n        // Returns true if this font family has a variaion sequence table (cmap format\n        // 14 subtable).\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool hasVSTable() const\n        public bool hasVSTable()\n        {\n            return mHasVSTable;\n        }\n\n        // Creates new FontFamily based on this family while applying font variations.\n        // Returns nullptr if none of variations apply to this family.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: FontFamily createFamilyWithVariation(const ClassicVector<FontVariation>& variations) const;\n        public FontFamily createFamilyWithVariation(List<FontVariation> variations)\n        {\n            if (variations.Count == 0 || mSupportedAxes.empty())\n            {\n                return null;\n            }\n\n            bool hasSupportedAxis = false;\n            foreach (FontVariation variation in variations)\n            {\n                if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end())\n                {\n                    hasSupportedAxis = true;\n                    break;\n                }\n            }\n            if (!hasSupportedAxis)\n            {\n                // None of variation axes are suppored by this family.\n                return null;\n            }\n\n            List<Font> fonts = new List<Font>();\n            foreach (Font font in mFonts)\n            {\n                bool supportedVariations = false;\n                std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n                HashSet<AxisTag> supportedAxes = font.getSupportedAxesLocked();\n                if (supportedAxes.Count > 0)\n                {\n                    foreach (FontVariation variation in variations)\n                    {\n                        if (supportedAxes.find(variation.axisTag) != supportedAxes.end())\n                        {\n                            supportedVariations = true;\n                            break;\n                        }\n                    }\n                }\n                MinikinFont minikinFont;\n                if (supportedVariations)\n                {\n                    minikinFont = font.typeface.createFontWithVariation(variations);\n                }\n                if (minikinFont == null)\n                {\n                    minikinFont = font.typeface;\n                }\n                fonts.Add(Font(std::move(minikinFont), font.style));\n            }\n\n            return new FontFamily(mLangId, mVariant, std::move(fonts));\n        }\n\n        public void computeCoverage()\n        {\n            std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n            FontStyle defaultStyle = new FontStyle();\n            MinikinFont typeface = getClosestMatch(defaultStyle).font;\n            uint cmapTag = MinikinFont.MakeTag('c', 'm', 'a', 'p');\n            HbBlob cmapTable = new HbBlob(getFontTable(typeface, new uint(cmapTag)));\n            if (cmapTable.get() == null)\n            {\n                ALOGE(\"Could not get cmap table size!\\n\");\n                return;\n            }\n            mCoverage = CmapCoverage.getCoverage(cmapTable.get(), cmapTable.size(), mHasVSTable);\n\n            for (int i = 0; i < mFonts.size(); ++i)\n            {\n                HashSet<AxisTag> supportedAxes = mFonts[i].getSupportedAxesLocked();\n                mSupportedAxes.insert(supportedAxes.GetEnumerator(), supportedAxes.end());\n            }\n        }\n\n        private uint mLangId = new uint();\n        private int mVariant;\n        private List<Font> mFonts = new List<Font>();\n        private HashSet<AxisTag> mSupportedAxes = new HashSet<AxisTag>();\n\n        private SparseBitSet mCoverage = new SparseBitSet();\n        private bool mHasVSTable;\n\n        // Forbid copying and assignment.\n        //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n        //  FontFamily(const FontFamily&) = delete;\n        //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n        //  void operator =(const FontFamily&) = delete;\n    }\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontLanguage.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\nnamespace minikin\n{\n\n// FontLanguage is a compact representation of a BCP 47 language tag. It\n// does not capture all possible information, only what directly affects\n// font rendering.\npublic class FontLanguage\n{\n  public enum EmojiStyle : byte\n  {\n\tEMSTYLE_EMPTY = 0,\n\tEMSTYLE_DEFAULT = 1,\n\tEMSTYLE_EMOJI = 2,\n\tEMSTYLE_TEXT = 3,\n  }\n  // Default constructor creates the unsupported language.\n  public FontLanguage()\n  {\n\t  this.mScript = 0U;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mLanguage = INVALID_CODE;\n\t  this.mLanguage.CopyFrom(GlobalMembers.INVALID_CODE);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mRegion = INVALID_CODE;\n\t  this.mRegion.CopyFrom(GlobalMembers.INVALID_CODE);\n\t  this.mHbLanguage = HB_LANGUAGE_INVALID;\n\t  this.mSubScriptBits = 0U;\n\t  this.mEmojiStyle = new minikin.FontLanguage.EmojiStyle.EMSTYLE_EMPTY;\n  }\n\n  // Parse from string\n\n  // Parse BCP 47 language identifier into internal structure\n  public FontLanguage(string buf, int length) : this()\n  {\n\tint firstDelimiterPos = minikin.GlobalMembers.nextDelimiterIndex(buf, length, 0);\n\tif (minikin.GlobalMembers.isValidLanguageCode(buf, firstDelimiterPos))\n\t{\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: mLanguage = packLanguageOrRegion(buf, firstDelimiterPos, 'a', 'a');\n\t  mLanguage.CopyFrom(minikin.GlobalMembers.packLanguageOrRegion(buf, firstDelimiterPos, 'a', 'a'));\n\t}\n\telse\n\t{\n\t  // We don't understand anything other than two-letter or three-letter\n\t  // language codes, so we skip parsing the rest of the string.\n\t  return;\n\t}\n\n\tif (firstDelimiterPos == length)\n\t{\n\t  mHbLanguage = hb_language_from_string(getString(), -1);\n\t  return; // Language code only.\n\t}\n\n\tint nextComponentStartPos = firstDelimiterPos + 1;\n\tint nextDelimiterPos = minikin.GlobalMembers.nextDelimiterIndex(buf, length, nextComponentStartPos);\n\tint componentLength = nextDelimiterPos - nextComponentStartPos;\n\n\tif (componentLength == 4)\n\t{\n\t  // Possibly script code.\n\t  string p = buf + nextComponentStartPos;\n\t  if (minikin.GlobalMembers.isValidScriptCode(p))\n\t  {\n\t\tmScript = (((uint)(p[0])) << 24 | ((uint)(p[1])) << 16 | ((uint)(p[2])) << 8 | ((uint)(p[3])));\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: mSubScriptBits = scriptToSubScriptBits(mScript);\n\t\tmSubScriptBits.CopyFrom(scriptToSubScriptBits(new uint(mScript)));\n\t  }\n\n\t  if (nextDelimiterPos == length)\n\t  {\n\t\tmHbLanguage = hb_language_from_string(getString(), -1);\n\t\tmEmojiStyle = resolveEmojiStyle(buf, length, new uint(mScript));\n\t\treturn; // No region code.\n\t  }\n\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: nextComponentStartPos = nextDelimiterPos + 1;\n\t  nextComponentStartPos.CopyFrom(nextDelimiterPos + 1);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: nextDelimiterPos = nextDelimiterIndex(buf, length, nextComponentStartPos);\n\t  nextDelimiterPos.CopyFrom(minikin.GlobalMembers.nextDelimiterIndex(buf, length, nextComponentStartPos));\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: componentLength = nextDelimiterPos - nextComponentStartPos;\n\t  componentLength.CopyFrom(nextDelimiterPos - nextComponentStartPos);\n\t}\n\n\tif (componentLength == 2 || componentLength == 3)\n\t{\n\t  // Possibly region code.\n\t  string p = buf + nextComponentStartPos;\n\t  if (minikin.GlobalMembers.isValidRegionCode(p, componentLength))\n\t  {\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: mRegion = packLanguageOrRegion(p, componentLength, 'A', '0');\n\t\tmRegion.CopyFrom(minikin.GlobalMembers.packLanguageOrRegion(p, componentLength, 'A', '0'));\n\t  }\n\t}\n\n\tmHbLanguage = hb_language_from_string(getString(), -1);\n\tmEmojiStyle = resolveEmojiStyle(buf, length, new uint(mScript));\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool operator ==(const FontLanguage other) const\n  public static bool operator == (FontLanguage ImpliedObject, FontLanguage other)\n  {\n\treturn !ImpliedObject.isUnsupported() && ImpliedObject.isEqualScript(other) && ImpliedObject.mLanguage == other.mLanguage && ImpliedObject.mRegion == other.mRegion && ImpliedObject.mEmojiStyle == other.mEmojiStyle;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool operator !=(const FontLanguage other) const\n  public static bool operator != (FontLanguage ImpliedObject, FontLanguage other)\n  {\n\t  return !(*ImpliedObject == other);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool isUnsupported() const\n  public bool isUnsupported()\n  {\n\t  return mLanguage == GlobalMembers.INVALID_CODE;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: EmojiStyle getEmojiStyle() const\n  public EmojiStyle getEmojiStyle()\n  {\n\t  return mEmojiStyle;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: hb_language_t getHbLanguage() const\n  public hb_language_t getHbLanguage()\n  {\n\t  return mHbLanguage;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool isEqualScript(const FontLanguage& other) const\n  public bool isEqualScript(FontLanguage other)\n  {\n\treturn other.mScript == mScript;\n  }\n\n  // Returns true if this script supports the given script. For example, ja-Jpan\n  // supports Hira, ja-Hira doesn't support Jpan.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool supportsHbScript(hb_script_t script) const\n  public bool supportsHbScript(hb_script_t script)\n  {\n  //C++ TO C# CONVERTER TODO TASK: There is no equivalent in C# to 'static_assert':\n  //  static_assert((((uint)('J')) << 24 | ((uint)('p')) << 16 | ((uint)('a')) << 8 | ((uint)('n'))) == HB_TAG('J', 'p', 'a', 'n'), \"The Minikin script and HarfBuzz hb_script_t have different encodings.\");\n\tif (script == mScript)\n\t{\n\t  return true;\n\t}\n\treturn supportsScript(new byte(mSubScriptBits), scriptToSubScriptBits(new hb_script_t(script)));\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: string getString() const\n  public string getString()\n  {\n\tif (isUnsupported())\n\t{\n\t  return \"und\";\n\t}\n\tstring buf = new string(new char[16]);\n\tint i = minikin.GlobalMembers.unpackLanguageOrRegion(new UInt16(mLanguage), ref buf, 'a', 'a');\n\tif (mScript != 0)\n\t{\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, '-');\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, (mScript >> 24) & 0xFFu);\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, (mScript >> 16) & 0xFFu);\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, (mScript >> 8) & 0xFFu);\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, mScript & 0xFFu);\n\t}\n\tif (mRegion != GlobalMembers.INVALID_CODE)\n\t{\n\t  buf = StringFunctions.ChangeCharacter(buf, i++, '-');\n\t  i += minikin.GlobalMembers.unpackLanguageOrRegion(new UInt16(mRegion), ref buf + i, 'A', '0');\n\t}\n\treturn (string)(buf, i);\n  }\n\n  // Calculates a matching score. This score represents how well the input\n  // languages cover this language. The maximum score in the language list is\n  // returned. 0 = no match, 1 = script match, 2 = script and primary language\n  // match.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int calcScoreFor(const FontLanguages& supported) const\n  public int calcScoreFor(FontLanguages supported)\n  {\n\tbool languageScriptMatch = false;\n\tbool subtagMatch = false;\n\tbool scriptMatch = false;\n\n\tfor (int i = 0; i < supported.size(); ++i)\n\t{\n\t  if (mEmojiStyle != EmojiStyle.EMSTYLE_EMPTY && mEmojiStyle == supported[i].mEmojiStyle)\n\t  {\n\t\tsubtagMatch = true;\n\t\tif (mLanguage == supported[i].mLanguage)\n\t\t{\n\t\t  return 4;\n\t\t}\n\t  }\n\t  if (isEqualScript(supported[i]) || supportsScript(supported[i].mSubScriptBits, new byte(mSubScriptBits)))\n\t  {\n\t\tscriptMatch = true;\n\t\tif (mLanguage == supported[i].mLanguage)\n\t\t{\n\t\t  languageScriptMatch = true;\n\t\t}\n\t  }\n\t}\n\n\tif (supportsScript(supported.getUnionOfSubScriptBits(), new byte(mSubScriptBits)))\n\t{\n\t  scriptMatch = true;\n\t  if (mLanguage == supported[0].mLanguage && supported.isAllTheSameLanguage())\n\t  {\n\t\treturn 3;\n\t  }\n\t}\n\n\tif (languageScriptMatch)\n\t{\n\t  return 3;\n\t}\n\telse if (subtagMatch)\n\t{\n\t  return 2;\n\t}\n\telse if (scriptMatch)\n\t{\n\t  return 1;\n\t}\n\treturn 0;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: UInt64 getIdentifier() const\n  public UInt64 getIdentifier()\n  {\n\treturn ((UInt64)mLanguage << 49) | ((UInt64)mScript << 17) | ((UInt64)mRegion << 2) | (int)mEmojiStyle;\n  }\n\n//C++ TO C# CONVERTER TODO TASK: C# has no concept of a 'friend' class:\n//  friend class FontLanguages; // for FontLanguages constructor\n\n  // ISO 15924 compliant script code. The 4 chars script code are packed into a\n  // 32 bit integer.\n  private uint mScript = new uint();\n\n  // ISO 639-1 or ISO 639-2 compliant language code.\n  // The two- or three-letter language code is packed into a 15 bit integer.\n  // mLanguage = 0 means the FontLanguage is unsupported.\n  private UInt16 mLanguage = new UInt16();\n\n  // ISO 3166-1 or UN M.49 compliant region code. The two-letter or three-digit\n  // region code is packed into a 15 bit integer.\n  private UInt16 mRegion = new UInt16();\n\n  // The language to be passed HarfBuzz shaper.\n  private hb_language_t mHbLanguage = new hb_language_t();\n\n  // For faster comparing, use 7 bits for specific scripts.\n  private const byte kBopomofoFlag = 1u;\n  private byte kHanFlag = 1u << 1;\n  private byte kHangulFlag = 1u << 2;\n  private byte kHiraganaFlag = 1u << 3;\n  private byte kKatakanaFlag = 1u << 4;\n  private byte kSimplifiedChineseFlag = 1u << 5;\n  private byte kTraditionalChineseFlag = 1u << 6;\n  private byte mSubScriptBits = new byte();\n\n  private EmojiStyle mEmojiStyle;\n\n\n  // static\n  private static byte scriptToSubScriptBits(uint script)\n  {\n\tbyte subScriptBits = 0u;\n\tswitch (script)\n\t{\n\t  case (((uint)('B')) << 24 | ((uint)('o')) << 16 | ((uint)('p')) << 8 | ((uint)('o'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kBopomofoFlag;\n\t\tsubScriptBits.CopyFrom(kBopomofoFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('g'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHangulFlag;\n\t\tsubScriptBits.CopyFrom(kHangulFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('b'))):\n\t\t// Bopomofo is almost exclusively used in Taiwan.\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag | kBopomofoFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag | kBopomofoFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('i'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('s'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag | kSimplifiedChineseFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag | kSimplifiedChineseFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('t'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag | kTraditionalChineseFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag | kTraditionalChineseFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('i')) << 16 | ((uint)('r')) << 8 | ((uint)('a'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHiraganaFlag;\n\t\tsubScriptBits.CopyFrom(kHiraganaFlag);\n\t\tbreak;\n\t  case (((uint)('H')) << 24 | ((uint)('r')) << 16 | ((uint)('k')) << 8 | ((uint)('t'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kKatakanaFlag | kHiraganaFlag;\n\t\tsubScriptBits.CopyFrom(kKatakanaFlag | kHiraganaFlag);\n\t\tbreak;\n\t  case (((uint)('J')) << 24 | ((uint)('p')) << 16 | ((uint)('a')) << 8 | ((uint)('n'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag | kKatakanaFlag | kHiraganaFlag);\n\t\tbreak;\n\t  case (((uint)('K')) << 24 | ((uint)('a')) << 16 | ((uint)('n')) << 8 | ((uint)('a'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kKatakanaFlag;\n\t\tsubScriptBits.CopyFrom(kKatakanaFlag);\n\t\tbreak;\n\t  case (((uint)('K')) << 24 | ((uint)('o')) << 16 | ((uint)('r')) << 8 | ((uint)('e'))):\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: subScriptBits = kHanFlag | kHangulFlag;\n\t\tsubScriptBits.CopyFrom(kHanFlag | kHangulFlag);\n\t\tbreak;\n\t}\n\treturn subScriptBits;\n  }\n\n\n  // static\n  private static FontLanguage.EmojiStyle resolveEmojiStyle(string buf, int length, uint script)\n  {\n\t// First, lookup emoji subtag.\n\t// 10 is the length of \"-u-em-text\", which is the shortest emoji subtag,\n\t// unnecessary comparison can be avoided if total length is smaller than 10.\n\tconst int kMinSubtagLength = 10;\n\tif (length >= kMinSubtagLength)\n\t{\n\t  const string kPrefix = \"-u-em-\";\n//C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged:\n\t  char * pos = std::search(buf, buf + length, kPrefix, kPrefix.Substring(kPrefix.Length));\n\t  if (pos != buf + length)\n\t  { // found\n\t\tpos += kPrefix.Length;\n\t\tint remainingLength = length - (pos - buf);\n\t\tif (minikin.GlobalMembers.isEmojiSubtag(pos, remainingLength, \"emoji\", 5))\n\t\t{\n\t\t  return EmojiStyle.EMSTYLE_EMOJI;\n\t\t}\n\t\telse if (minikin.GlobalMembers.isEmojiSubtag(pos, remainingLength, \"text\", 4))\n\t\t{\n\t\t  return EmojiStyle.EMSTYLE_TEXT;\n\t\t}\n\t\telse if (minikin.GlobalMembers.isEmojiSubtag(pos, remainingLength, \"default\", 7))\n\t\t{\n\t\t  return EmojiStyle.EMSTYLE_DEFAULT;\n\t\t}\n\t  }\n\t}\n\n\t// If no emoji subtag was provided, resolve the emoji style from script code.\n\tif (script == (((uint)('Z')) << 24 | ((uint)('s')) << 16 | ((uint)('y')) << 8 | ((uint)('e'))))\n\t{\n\t  return EmojiStyle.EMSTYLE_EMOJI;\n\t}\n\telse if (script == (((uint)('Z')) << 24 | ((uint)('s')) << 16 | ((uint)('y')) << 8 | ((uint)('m'))))\n\t{\n\t  return EmojiStyle.EMSTYLE_TEXT;\n\t}\n\n\treturn EmojiStyle.EMSTYLE_EMPTY;\n  }\n\n  // Returns true if the provide subscript bits has the requested subscript\n  // bits. Note that this function returns false if the requested subscript bits\n  // are empty.\n\n  // static\n  private static bool supportsScript(byte providedBits, byte requestedBits)\n  {\n\treturn requestedBits != 0 && (providedBits & requestedBits) == requestedBits;\n  }\n}\n\n// An immutable list of languages.\npublic class FontLanguages\n{\n//C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n  public FontLanguages(List<FontLanguage>&& languages)\n  {\n\t  this.mLanguages = std::move(languages);\n\tif (mLanguages.Count == 0)\n\t{\n\t  return;\n\t}\n\n\tFontLanguage lang = mLanguages[0];\n\n\tmIsAllTheSameLanguage = true;\n\tmUnionOfSubScriptBits = lang.mSubScriptBits;\n\tfor (int i = 1; i < mLanguages.Count; ++i)\n\t{\n\t  mUnionOfSubScriptBits |= mLanguages[i].mSubScriptBits;\n\t  if (mIsAllTheSameLanguage && lang.mLanguage != mLanguages[i].mLanguage)\n\t  {\n\t\tmIsAllTheSameLanguage = false;\n\t  }\n\t}\n  }\n  public FontLanguages()\n  {\n\t  this.mUnionOfSubScriptBits = 0;\n\t  this.mIsAllTheSameLanguage = false;\n  }\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//  FontLanguages(FontLanguages&&) = default;\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int size() const\n  public int size()\n  {\n\t  return mLanguages.Count;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool empty() const\n  public bool empty()\n  {\n\t  return mLanguages.Count == 0;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const FontLanguage& operator [](int n) const\n  public FontLanguage this[int n]\n  {\n\t  get\n\t  {\n\t\t  return mLanguages[n];\n\t  }\n\t  set\n\t  {\n\t\t  mLanguages[n] = value;\n\t  }\n  }\n\n//C++ TO C# CONVERTER TODO TASK: C# has no concept of a 'friend' class:\n//  friend struct FontLanguage; // for calcScoreFor\n\n  private List<FontLanguage> mLanguages = new List<FontLanguage>();\n  private byte mUnionOfSubScriptBits = new byte();\n  private bool mIsAllTheSameLanguage;\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: byte getUnionOfSubScriptBits() const\n  private byte getUnionOfSubScriptBits()\n  {\n\t  return mUnionOfSubScriptBits;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool isAllTheSameLanguage() const\n  private bool isAllTheSameLanguage()\n  {\n\t  return mIsAllTheSameLanguage;\n  }\n\n  // Do not copy and assign.\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  FontLanguages(const FontLanguages&) = delete;\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  void operator =(const FontLanguages&) = delete;\n}\n\n} // namespace minikin\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontLanguageListCache.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\nnamespace minikin\n{\n\npublic class FontLanguageListCache : System.IDisposable\n{\n  // A special ID for the empty language list.\n  // This value must be 0 since the empty language list is inserted into\n  // mLanguageLists by default.\n  public const uint kEmptyListId = 0;\n\n  // Returns language list ID for the given string representation of\n  // FontLanguages. Caller should acquire a lock before calling the method.\n\n  // static\n  public static uint getId(string languages)\n  {\n\tFontLanguageListCache inst = FontLanguageListCache.getInstance();\n\tDictionary<string, uint>.Enumerator it = inst.mLanguageListLookupTable.find(languages);\n//C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n\tif (it != inst.mLanguageListLookupTable.end())\n\t{\n//C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n\t  return it.second;\n\t}\n\n\t// Given language list is not in cache. Insert it and return newly assigned\n\t// ID.\n\tuint nextId = inst.mLanguageLists.Count;\n\tFontLanguages fontLanguages = new FontLanguages(minikin.GlobalMembers.parseLanguageList(languages));\n\tif (fontLanguages.empty())\n\t{\n\t  return kEmptyListId;\n\t}\n\tinst.mLanguageLists.Add(std::move(fontLanguages));\n\tinst.mLanguageListLookupTable.Add(languages, nextId);\n\treturn nextId;\n  }\n\n  // Caller should acquire a lock before calling the method.\n\n  // static\n  public static FontLanguages getById(uint id)\n  {\n\tFontLanguageListCache inst = FontLanguageListCache.getInstance();\n\tLOG_ALWAYS_FATAL_IF(id >= inst.mLanguageLists.Count, \"Lookup by unknown language list ID.\");\n\treturn inst.mLanguageLists[id];\n  }\n\n  private FontLanguageListCache()\n  {\n  } // Singleton\n  public void Dispose()\n  {\n  }\n\n  // Caller should acquire a lock before calling the method.\n\n  // static\n//C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n  private static FontLanguageListCache getInstance_instance = null;\n  private static FontLanguageListCache getInstance()\n  {\n\tassertMinikinLocked();\n//C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n//\tstatic FontLanguageListCache* instance = null;\n\tif (getInstance_instance == null)\n\t{\n\t  getInstance_instance = new FontLanguageListCache();\n\n\t  // Insert an empty language list for mapping default language list to\n\t  // kEmptyListId. The default language list has only one FontLanguage and it\n\t  // is the unsupported language.\n\t  getInstance_instance.mLanguageLists.Add(new FontLanguages());\n\t  getInstance_instance.mLanguageListLookupTable.Add(\"\", kEmptyListId);\n\t}\n\treturn getInstance_instance;\n  }\n\n  private List<FontLanguages> mLanguageLists = new List<FontLanguages>();\n\n  // A map from string representation of the font language list to the ID.\n  private Dictionary<string, uint> mLanguageListLookupTable = new Dictionary<string, uint>();\n}\n\n} // namespace minikin\n\n\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/FontUtils.cs",
    "content": "﻿/*\n * Copyright (C) 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright (C) 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/GlobalMembers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace minikin\n{\n    public static class GlobalMembers\n    {\n        // These could perhaps be optimized to use __builtin_bswap16 and friends.\n        internal static uint readU16(byte[] data, int offset)\n        {\n            return ((uint)data[offset]) << 8 | ((uint)data[offset + 1]);\n        }\n\n        internal static uint readU32(byte[] data, int offset)\n        {\n            return ((uint)data[offset]) << 24 | ((uint)data[offset + 1]) << 16 | ((uint)data[offset + 2]) << 8 | ((uint)data[offset + 3]);\n        }\n\n        internal static void addRange(vector<uint> coverage, uint start, uint end)\n        {\n#if VERBOSE_DEBUG\n\t  ALOGD(\"adding range %d-%d\\n\", start, end);\n#endif\n            if (coverage.empty() || coverage.back() < start)\n            {\n                coverage.push_back(start);\n                coverage.push_back(end);\n            }\n            else\n            {\n                coverage.back() = end;\n            }\n        }\n\n        // Get the coverage information out of a Format 4 subtable, storing it in the\n        // coverage vector\n        internal static bool getCoverageFormat4(vector<uint> coverage, byte data, int size)\n        {\n            const int kSegCountOffset = 6;\n            const int kEndCountOffset = 14;\n            const int kHeaderSize = 16;\n            const int kSegmentSize = 8; // total size of array elements for one segment\n            if (kEndCountOffset > size)\n            {\n                return false;\n            }\n            int segCount = readU16(data, kSegCountOffset) >> 1;\n            if (kHeaderSize + segCount * kSegmentSize > size != null)\n            {\n                return false;\n            }\n            for (int i = 0; i < segCount; i++)\n            {\n                uint end = readU16(data, kEndCountOffset + 2 * i);\n                uint start = readU16(data, kHeaderSize + 2 * (segCount + i));\n                if (end < start)\n                {\n                    // invalid segment range: size must be positive\n                    android_errorWriteLog(0x534e4554, \"26413177\");\n                    return false;\n                }\n                uint rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));\n                if (rangeOffset == 0)\n                {\n                    uint delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));\n                    if (((end + delta) & 0xffff) > end - start)\n                    {\n                        addRange(coverage, new uint(start), end + 1);\n                    }\n                    else\n                    {\n                        for (uint j = start; j < end + 1; j++)\n                        {\n                            if (((j + delta) & 0xffff) != 0)\n                            {\n                                addRange(coverage, new uint(j), j + 1);\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    for (uint j = start; j < end + 1; j++)\n                    {\n                        uint actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset + (i + j - start) * 2;\n                        if (actualRangeOffset + 2 > size != null)\n                        {\n                            // invalid rangeOffset is considered a \"warning\" by OpenType Sanitizer\n                            continue;\n                        }\n                        uint glyphId = readU16(data, new uint(actualRangeOffset));\n                        if (glyphId != 0)\n                        {\n                            addRange(coverage, new uint(j), j + 1);\n                        }\n                    }\n                }\n            }\n            return true;\n        }\n\n        // Get the coverage information out of a Format 12 subtable, storing it in the\n        // coverage vector\n        internal static bool getCoverageFormat12(vector<uint> coverage, byte data, int size)\n        {\n            const int kNGroupsOffset = 12;\n            const int kFirstGroupOffset = 16;\n            const int kGroupSize = 12;\n            const int kStartCharCodeOffset = 0;\n            const int kEndCharCodeOffset = 4;\n            int kMaxNGroups = 0xfffffff0 / kGroupSize; // protection against overflow\n                                                       // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits\n                                                       // in 32 bits.\n            if (kFirstGroupOffset > size)\n            {\n                return false;\n            }\n            uint nGroups = readU32(data, kNGroupsOffset);\n            if (nGroups >= kMaxNGroups != null || kFirstGroupOffset + nGroups * kGroupSize > size)\n            {\n                android_errorWriteLog(0x534e4554, \"25645298\");\n                return false;\n            }\n            for (uint i = 0; i < nGroups; i++)\n            {\n                uint groupOffset = kFirstGroupOffset + i * kGroupSize;\n                uint start = readU32(data, groupOffset + kStartCharCodeOffset);\n                uint end = readU32(data, groupOffset + kEndCharCodeOffset);\n                if (end < start)\n                {\n                    // invalid group range: size must be positive\n                    android_errorWriteLog(0x534e4554, \"26413177\");\n                    return false;\n                }\n\n                // No need to read outside of Unicode code point range.\n                if (start > MAX_UNICODE_CODE_POINT)\n                {\n                    return true;\n                }\n                if (end > MAX_UNICODE_CODE_POINT)\n                {\n                    // file is inclusive, vector is exclusive\n                    addRange(coverage, new uint(start), MAX_UNICODE_CODE_POINT + 1);\n                    return true;\n                }\n                addRange(coverage, new uint(start), end + 1); // file is inclusive, vector is exclusive\n            }\n            return true;\n        }\n\n        // Lower value has higher priority. 0 for the highest priority table.\n        // kLowestPriority for unsupported tables.\n        // This order comes from HarfBuzz's hb-ot-font.cc and needs to be kept in sync\n        // with it.\n        public const byte kLowestPriority = 255;\n        public static byte getTablePriority(UInt16 platformId, UInt16 encodingId)\n        {\n            if (platformId == 3 && encodingId == 10)\n            {\n                return 0;\n            }\n            if (platformId == 0 && encodingId == 6)\n            {\n                return 1;\n            }\n            if (platformId == 0 && encodingId == 4)\n            {\n                return 2;\n            }\n            if (platformId == 3 && encodingId == 1)\n            {\n                return 3;\n            }\n            if (platformId == 0 && encodingId == 3)\n            {\n                return 4;\n            }\n            if (platformId == 0 && encodingId == 2)\n            {\n                return 5;\n            }\n            if (platformId == 0 && encodingId == 1)\n            {\n                return 6;\n            }\n            if (platformId == 0 && encodingId == 0)\n            {\n                return 7;\n            }\n            // Tables other than above are not supported.\n            return kLowestPriority;\n        }\n\n        public static bool isEmoji(uint c)\n        {\n            return u_hasBinaryProperty(c, UCHAR_EMOJI);\n        }\n\n        public static bool isEmojiModifier(uint c)\n        {\n            return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER);\n        }\n\n        public static bool isEmojiBase(uint c)\n        {\n            // These two characters were removed from Emoji_Modifier_Base in Emoji 4.0,\n            // but we need to keep them as emoji modifier bases since there are fonts and\n            // user-generated text out there that treats these as potential emoji bases.\n            if (c == 0x1F91D || c == 0x1F93C)\n            {\n                return true;\n            }\n            return u_hasBinaryProperty(c, UCHAR_EMOJI_MODIFIER_BASE);\n        }\n\n        public static UCharDirection emojiBidiOverride(object UnnamedParameter, UChar32 c)\n        {\n            return u_charDirection(c);\n        }\n        internal static T max<T>(T a, T b)\n        {\n            return a > b != null ? a : b;\n        }\n\n        public static readonly uint EMOJI_STYLE_VS = 0xFE0F;\n        public static readonly uint TEXT_STYLE_VS = 0xFE0E;\n\n        public static uint FontCollection.sNextId = 0;\n\n        // libtxt: return a locale string for a language list ID\n        public static string GetFontLocale(uint langListId)\n        {\n            FontLanguages langs = FontLanguageListCache.getById(new uint(langListId));\n            return langs.size() != null ? langs[0].getString() : \"\";\n        }\n\n        // Special scores for the font fallback.\n        public static readonly uint kUnsupportedFontScore = 0;\n        public static readonly uint kFirstFontScore = UINT32_MAX;\n\n        public static readonly uint NBSP = 0x00A0;\n        public static readonly uint SOFT_HYPHEN = 0x00AD;\n        public static readonly uint ZWJ = 0x200C;\n        public static readonly uint ZWNJ = 0x200D;\n        public static readonly uint HYPHEN = 0x2010;\n        public static readonly uint NB_HYPHEN = 0x2011;\n        public static readonly uint NNBSP = 0x202F;\n        public static readonly uint FEMALE_SIGN = 0x2640;\n        public static readonly uint MALE_SIGN = 0x2642;\n        public static readonly uint STAFF_OF_AESCULAPIUS = 0x2695;\n\n        // Characters where we want to continue using existing font run instead of\n        // recomputing the best match in the fallback list.\n        internal uint[] stickyWhitelist = { '!', ',', '-', '.', ':', ';', '?', NBSP, ZWJ, ZWNJ, HYPHEN, NB_HYPHEN, NNBSP, FEMALE_SIGN, MALE_SIGN, STAFF_OF_AESCULAPIUS };\n\n        internal static bool isStickyWhitelisted(uint c)\n        {\n            //C++ TO C# CONVERTER WARNING: This 'sizeof' ratio was replaced with a direct reference to the array length:\n            //ORIGINAL LINE: for (int i = 0; i < sizeof(stickyWhitelist) / sizeof(stickyWhitelist[0]); i++)\n            for (int i = 0; i < stickyWhitelist.Length; i++)\n            {\n                if (stickyWhitelist[i] == c)\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        internal static bool isVariationSelector(uint c)\n        {\n            return (0xFE00 <= c != null && c <= 0xFE0F) || (0xE0100 <= c != null && c <= 0xE01EF);\n        }\n\n        // Compute a matching metric between two styles - 0 is an exact match\n        internal static int computeMatch(FontStyle style1, FontStyle style2)\n        {\n            if (style1 == style2)\n            {\n                return 0;\n            }\n            int score = Math.Abs(style1.getWeight() - style2.getWeight());\n            if (style1.getItalic() != style2.getItalic())\n            {\n                score += 2;\n            }\n            return score;\n        }\n\n        internal static FontFakery computeFakery(FontStyle wanted, FontStyle actual)\n        {\n            // If desired weight is semibold or darker, and 2 or more grades\n            // higher than actual (for example, medium 500 -> bold 700), then\n            // select fake bold.\n            int wantedWeight = wanted.getWeight();\n            bool isFakeBold = wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2;\n            bool isFakeItalic = wanted.getItalic() && !actual.getItalic();\n            return FontFakery(isFakeBold, isFakeItalic);\n        }\n\n        // Due to the limits in font fallback score calculation, we can't use anything\n        // more than 12 languages.\n        public static readonly int FONT_LANGUAGES_LIMIT = 12;\n\n        // The language or region code is encoded to 15 bits.\n        public static readonly UInt16 INVALID_CODE = 0x7fff;\n\n        //C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n        //class FontLanguages;\n\n        //C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n        //ORIGINAL LINE: #define SCRIPT_TAG(c1, c2, c3, c4) (((uint)(c1)) << 24 | ((uint)(c2)) << 16 | ((uint)(c3)) << 8 | ((uint)(c4)))\n\n        // Check if a language code supports emoji according to its subtag\n        internal static bool isEmojiSubtag(string buf, int bufLen, string subtag, int subtagLen)\n        {\n            if (bufLen < subtagLen)\n            {\n                return false;\n            }\n            if (string.Compare(buf, 0, subtag, 0, subtagLen) != 0)\n            {\n                return false; // no match between two strings\n            }\n            return (bufLen == subtagLen || buf[subtagLen] == '\\0' || buf[subtagLen] == '-' || buf[subtagLen] == '_');\n        }\n\n        // Pack the three letter code into 15 bits and stored to 16 bit integer. The\n        // highest bit is 0. For the region code, the letters must be all digits in\n        // three letter case, so the number of possible values are 10. For the language\n        // code, the letters must be all small alphabets, so the number of possible\n        // values are 26. Thus, 5 bits are sufficient for each case and we can pack the\n        // three letter language code or region code to 15 bits.\n        //\n        // In case of two letter code, use fullbit(0x1f) for the first letter instead.\n        internal static UInt16 packLanguageOrRegion(string c, int length, byte twoLetterBase, byte threeLetterBase)\n        {\n            if (length == 2)\n            {\n                return 0x7c00u | (UInt16)(c[0] - twoLetterBase) << 5 | (UInt16)(c[1] - twoLetterBase);\n            }\n            else\n            {\n                return ((UInt16)(c[0] - threeLetterBase) << 10) | (UInt16)(c[1] - threeLetterBase) << 5 | (UInt16)(c[2] - threeLetterBase);\n            }\n        }\n\n        internal static int unpackLanguageOrRegion(UInt16 @in, ref string @out, byte twoLetterBase, byte threeLetterBase)\n        {\n            byte first = (@in >> 10) &0x1f;\n            byte second = (@in >> 5) &0x1f;\n            byte third = @in &0x1f;\n\n            if (first == 0x1f)\n            {\n                @out[0] = second + twoLetterBase;\n                @out[1] = third + twoLetterBase;\n                return 2;\n            }\n            else\n            {\n                @out[0] = first + threeLetterBase;\n                @out[1] = second + threeLetterBase;\n                @out[2] = third + threeLetterBase;\n                return 3;\n            }\n        }\n\n        // Find the next '-' or '_' index from startOffset position. If not found,\n        // returns bufferLength.\n        internal static int nextDelimiterIndex(string buffer, int bufferLength, int startOffset)\n        {\n            for (int i = startOffset; i < bufferLength; ++i)\n            {\n                if (buffer[i] == '-' || buffer[i] == '_')\n                {\n                    return i;\n                }\n            }\n            return bufferLength;\n        }\n\n        internal static bool isLowercase(char c)\n        {\n            return 'a' <= c && c <= 'z';\n        }\n\n        internal static bool isUppercase(char c)\n        {\n            return 'A' <= c && c <= 'Z';\n        }\n\n        internal static bool isDigit(char c)\n        {\n            return '0' <= c && c <= '9';\n        }\n\n        // Returns true if the buffer is valid for language code.\n        internal static bool isValidLanguageCode(string buffer, int length)\n        {\n            if (length != 2 && length != 3)\n            {\n                return false;\n            }\n            if (!isLowercase(buffer[0]))\n            {\n                return false;\n            }\n            if (!isLowercase(buffer[1]))\n            {\n                return false;\n            }\n            if (length == 3 && !isLowercase(buffer[2]))\n            {\n                return false;\n            }\n            return true;\n        }\n\n        // Returns true if buffer is valid for script code. The length of buffer must\n        // be 4.\n        internal static bool isValidScriptCode(string buffer)\n        {\n            return isUppercase(buffer[0]) && isLowercase(buffer[1]) && isLowercase(buffer[2]) && isLowercase(buffer[3]);\n        }\n\n        // Returns true if the buffer is valid for region code.\n        internal static bool isValidRegionCode(string buffer, int length)\n        {\n            return (length == 2 && isUppercase(buffer[0]) && isUppercase(buffer[1])) || (length == 3 && isDigit(buffer[0]) && isDigit(buffer[1]) && isDigit(buffer[2]));\n        }\n\n\n        // Returns the text length of output.\n        internal static int toLanguageTag(ref string output, int outSize, string locale)\n        {\n            output[0] = '\\0';\n            if (string.IsNullOrEmpty(locale))\n            {\n                return 0;\n            }\n\n            int outLength = 0;\n            UErrorCode uErr = U_ZERO_ERROR;\n            outLength = uloc_canonicalize(locale, output, outSize, uErr);\n            if (U_FAILURE(uErr))\n            {\n                // unable to build a proper language identifier\n                ALOGD(\"uloc_canonicalize(\\\"%s\\\") failed: %s\", locale, u_errorName(uErr));\n                output[0] = '\\0';\n                return 0;\n            }\n\n            // Preserve \"und\" and \"und-****\" since uloc_addLikelySubtags changes \"und\" to\n            // \"en-Latn-US\".\n            if (string.Compare(output, 0, \"und\", 0, 3) == 0 && (outLength == 3 || (outLength == 8 && output[3] == '_')))\n            {\n                return outLength;\n            }\n\n            string likelyChars = new string(new char[ULOC_FULLNAME_CAPACITY]);\n            uErr = U_ZERO_ERROR;\n            uloc_addLikelySubtags(output, likelyChars, ULOC_FULLNAME_CAPACITY, uErr);\n            if (U_FAILURE(uErr))\n            {\n                // unable to build a proper language identifier\n                ALOGD(\"uloc_addLikelySubtags(\\\"%s\\\") failed: %s\", output, u_errorName(uErr));\n                output[0] = '\\0';\n                return 0;\n            }\n\n            uErr = U_ZERO_ERROR;\n            outLength = uloc_toLanguageTag(likelyChars, output, outSize, 0, uErr);\n            if (U_FAILURE(uErr))\n            {\n                // unable to build a proper language identifier\n                ALOGD(\"uloc_toLanguageTag(\\\"%s\\\") failed: %s\", likelyChars, u_errorName(uErr));\n                output[0] = '\\0';\n                return 0;\n            }\n#if VERBOSE_DEBUG\n\t  ALOGD(\"ICU normalized '%s' to '%s'\", locale, output);\n#endif\n            return outLength;\n        }\n\n        internal static List<FontLanguage> parseLanguageList(string input)\n        {\n            List<FontLanguage> result = new List<FontLanguage>();\n            int currentIdx = 0;\n            int commaLoc = 0;\n            string langTag = new string(new char[ULOC_FULLNAME_CAPACITY]);\n            HashSet<UInt64> seen = new HashSet<UInt64>();\n            string locale = new string(input.Length, 0);\n\n            while ((commaLoc = input.IndexOfAny((Convert.ToString(',')).ToCharArray(), currentIdx)) != -1)\n            {\n                locale.assign(input, currentIdx, commaLoc - currentIdx);\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: currentIdx = commaLoc + 1;\n                currentIdx.CopyFrom(commaLoc + 1);\n                int length = toLanguageTag(ref langTag, ULOC_FULLNAME_CAPACITY, locale);\n                FontLanguage lang = new FontLanguage(langTag, length);\n                UInt64 identifier = lang.getIdentifier();\n                if (!lang.isUnsupported() && seen.count(identifier) == 0)\n                {\n                    result.Add(lang);\n                    if (result.Count == FONT_LANGUAGES_LIMIT)\n                    {\n                        break;\n                    }\n                    seen.Add(identifier);\n                }\n            }\n            if (result.Count < FONT_LANGUAGES_LIMIT)\n            {\n                locale.assign(input, currentIdx, input.Length - currentIdx);\n                int length = toLanguageTag(ref langTag, ULOC_FULLNAME_CAPACITY, locale);\n                FontLanguage lang = new FontLanguage(langTag, length);\n                UInt64 identifier = lang.getIdentifier();\n                if (!lang.isUnsupported() && seen.count(identifier) == 0)\n                {\n                    result.Add(lang);\n                }\n            }\n            return result;\n        }\n\n        public static bool analyzeStyle(byte os2_data, int os2_size, ref int weight, ref bool italic)\n        {\n            const int kUsWeightClassOffset = 4;\n            const int kFsSelectionOffset = 62;\n            UInt16 kItalicFlag = (1 << 0);\n            if (os2_size < kFsSelectionOffset + 2)\n            {\n                return false;\n            }\n            UInt16 weightClass = readU16(os2_data, kUsWeightClassOffset);\n            weight = weightClass / 100;\n            UInt16 fsSelection = readU16(os2_data, kFsSelectionOffset);\n            italic = (fsSelection & kItalicFlag) != 0;\n            return true;\n        }\n        public static void analyzeAxes(byte fvar_data, int fvar_size, HashSet<uint> axes)\n        {\n            const int kMajorVersionOffset = 0;\n            const int kMinorVersionOffset = 2;\n            const int kOffsetToAxesArrayOffset = 4;\n            const int kAxisCountOffset = 8;\n            const int kAxisSizeOffset = 10;\n\n            axes.Clear();\n\n            if (fvar_size < kAxisSizeOffset + 2)\n            {\n                return;\n            }\n            UInt16 majorVersion = readU16(fvar_data, kMajorVersionOffset);\n            UInt16 minorVersion = readU16(fvar_data, kMinorVersionOffset);\n            uint axisOffset = readU16(fvar_data, kOffsetToAxesArrayOffset);\n            uint axisCount = readU16(fvar_data, kAxisCountOffset);\n            uint axisSize = readU16(fvar_data, kAxisSizeOffset);\n\n            if (majorVersion != 1 || minorVersion != 0 || axisOffset != 0x10 || axisSize != 0x14)\n            {\n                return; // Unsupported version.\n            }\n            if (fvar_size < axisOffset + axisOffset * axisCount)\n            {\n                return; // Invalid table size.\n            }\n            for (uint i = 0; i < axisCount; ++i)\n            {\n                int axisRecordOffset = axisOffset + i * axisSize;\n                uint tag = readU32(fvar_data, axisRecordOffset);\n                axes.Add(tag);\n            }\n        }\n\n        internal static UInt16 readU16(byte[] data, int offset)\n        {\n            return data[offset] << 8 | data[offset + 1];\n        }\n\n        internal static uint readU32(byte[] data, int offset)\n        {\n            return ((uint)data[offset]) << 24 | ((uint)data[offset + 1]) << 16 | ((uint)data[offset + 2]) << 8 | ((uint)data[offset + 3]);\n        }\n\n        public static int tailoredGraphemeClusterBreak(uint c)\n        {\n            // Characters defined as Control that we want to treat them as Extend.\n            // These are curated manually.\n            if (c == 0x00AD || c == 0x061C || c == 0x180E || c == 0x200B || c == 0x200E || c == 0x200F || (0x202A <= c != null && c <= 0x202E) || ((c | 0xF) == 0x206F) || c == 0xFEFF || ((c | 0x7F) == 0xE007F)) // recently undeprecated tag characters in Plane 14\n            {\n                return U_GCB_EXTEND;\n            }\n            // THAI CHARACTER SARA AM is treated as a normal letter by most other\n            // implementations: they allow a grapheme break before it.\n            else if (c == 0x0E33)\n            {\n                return U_GCB_OTHER;\n            }\n            else\n            {\n                return u_getIntPropertyValue(c, UCHAR_GRAPHEME_CLUSTER_BREAK);\n            }\n        }\n\n        // Returns true for all characters whose IndicSyllabicCategory is Pure_Killer.\n        // From http://www.unicode.org/Public/9.0.0/ucd/IndicSyllabicCategory.txt\n        public static bool isPureKiller(uint c)\n        {\n            return (c == 0x0E3A || c == 0x0E4E || c == 0x0F84 || c == 0x103A || c == 0x1714 || c == 0x1734 || c == 0x17D1 || c == 0x1BAA || c == 0x1BF2 || c == 0x1BF3 || c == 0xA806 || c == 0xA953 || c == 0xABED || c == 0x11134 || c == 0x112EA || c == 0x1172B);\n        }\n\n        public static void purgeHbFontCacheLocked()\n        {\n            assertMinikinLocked();\n            getFontCacheLocked.functorMethod().clear();\n        }\n        public static void purgeHbFontLocked(MinikinFont minikinFont)\n        {\n            assertMinikinLocked();\n            int fontId = minikinFont.GetUniqueId();\n            getFontCacheLocked.functorMethod().remove(fontId);\n        }\n\n        // Returns a new reference to a HarfBuzzSharp.Font object, caller is\n        // responsible for calling hb_font_destroy() on it.\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static HarfBuzzSharp.Font getHbFontLocked_nullFaceFont = null;\n        public static HarfBuzzSharp.Font getHbFontLocked(MinikinFont minikinFont)\n        {\n            assertMinikinLocked();\n            // TODO: get rid of nullFaceFont\n            //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n            //  static HarfBuzzSharp.Font* nullFaceFont = null;\n            if (minikinFont == null)\n            {\n                if (getHbFontLocked_nullFaceFont == null)\n                {\n                    getHbFontLocked_nullFaceFont = hb_font_create(null);\n                }\n                return hb_font_reference(getHbFontLocked_nullFaceFont);\n            }\n\n            HbFontCache fontCache = getFontCacheLocked.functorMethod();\n            int fontId = minikinFont.GetUniqueId();\n            HarfBuzzSharp.Font font = fontCache.get(fontId);\n            if (font != null)\n            {\n                return hb_font_reference(font);\n            }\n\n            HarfBuzzSharp.Face face = minikinFont.CreateHarfBuzzFace();\n\n            HarfBuzzSharp.Font parent_font = hb_font_create(face);\n            hb_ot_font_set_funcs(parent_font);\n\n            uint upem = hb_face_get_upem(face);\n            hb_font_set_scale(parent_font, upem, upem);\n\n            font = hb_font_create_sub_font(parent_font);\n            List<hb_variation_t> variations = new List<hb_variation_t>();\n            foreach (FontVariation variation in minikinFont.GetAxes())\n            {\n                variations.Add({ variation.axisTag, variation.value});\n            }\n            hb_font_set_variations(font, variations.data(), variations.Count);\n            hb_font_destroy(parent_font);\n            hb_face_destroy(face);\n            fontCache.put(fontId, font);\n            return hb_font_reference(font);\n        }\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static HbFontCache getFontCacheLocked_cache = null;\n\n        public static HbFontCache getFontCacheLocked()\n        {\n            assertMinikinLocked();\n            //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n            //  static HbFontCache* cache = null;\n            if (getFontCacheLocked_cache == null)\n            {\n                getFontCacheLocked_cache = new HbFontCache();\n            }\n            return getFontCacheLocked_cache.functorMethod;\n        }\n\n        internal const UInt16 CHAR_HYPHEN_MINUS = 0x002D;\n        internal const UInt16 CHAR_SOFT_HYPHEN = 0x00AD;\n        internal const UInt16 CHAR_MIDDLE_DOT = 0x00B7;\n        internal const UInt16 CHAR_HYPHEN = 0x2010;\n\n        internal static uint[] HYPHEN_STR = { 0x2010, 0 };\n        internal static uint[] ARMENIAN_HYPHEN_STR = { 0x058A, 0 };\n        internal static uint[] MAQAF_STR = { 0x05BE, 0 };\n        internal static uint[] UCAS_HYPHEN_STR = { 0x1400, 0 };\n        internal static uint[] ZWJ_STR = { 0x200D, 0 };\n        internal static uint[] ZWJ_AND_HYPHEN_STR = { 0x200D, 0x2010, 0 };\n\n        internal static UScriptCode getScript(uint codePoint)\n        {\n            UErrorCode errorCode = U_ZERO_ERROR;\n            UScriptCode script = uscript_getScript((UChar32)codePoint, errorCode);\n            if (U_SUCCESS(errorCode))\n            {\n                return script;\n            }\n            else\n            {\n                return USCRIPT_INVALID_CODE;\n            }\n        }\n\n        internal static HyphenationType hyphenationTypeBasedOnScript(uint codePoint)\n        {\n            // Note: It's not clear what the best hyphen for Hebrew is. While maqaf is the\n            // \"correct\" hyphen for Hebrew, modern practice may have shifted towards\n            // Western hyphens. We use normal hyphens for now to be safe.\n            // BREAK_AND_INSERT_MAQAF is already implemented, so if we want to switch to\n            // maqaf for Hebrew, we can simply add a condition here.\n            UScriptCode script = getScript(new uint(codePoint));\n            if (script == USCRIPT_KANNADA || script == USCRIPT_MALAYALAM || script == USCRIPT_TAMIL || script == USCRIPT_TELUGU)\n            {\n                // Grantha is not included, since we don't support non-BMP hyphenation yet.\n                return HyphenationType.BREAK_AND_DONT_INSERT_HYPHEN;\n            }\n            else if (script == USCRIPT_ARMENIAN)\n            {\n                return HyphenationType.BREAK_AND_INSERT_ARMENIAN_HYPHEN;\n            }\n            else if (script == USCRIPT_CANADIAN_ABORIGINAL)\n            {\n                return HyphenationType.BREAK_AND_INSERT_UCAS_HYPHEN;\n            }\n            else\n            {\n                return HyphenationType.BREAK_AND_INSERT_HYPHEN;\n            }\n        }\n\n        internal static int getJoiningType(UChar32 codepoint)\n        {\n            return u_getIntPropertyValue(codepoint, UCHAR_JOINING_TYPE);\n        }\n\n        // Assumption for caller: location must be >= 2 and word[location] ==\n        // CHAR_SOFT_HYPHEN. This function decides if the letters before and after the\n        // hyphen should appear as joining.\n        internal static HyphenationType getHyphTypeForArabic(UInt16[] word, int len, int location)\n        {\n            IntPtr i = location;\n            int type = U_JT_NON_JOINING;\n            while ((int)i < len && (type = getJoiningType(word[i])) == U_JT_TRANSPARENT)\n            {\n                i++;\n            }\n            if (type == U_JT_DUAL_JOINING || type == U_JT_RIGHT_JOINING || type == U_JT_JOIN_CAUSING)\n            {\n                // The next character is of the type that may join the last character. See\n                // if the last character is also of the right type.\n                i = location - 2; // Skip the soft hyphen\n                type = U_JT_NON_JOINING;\n                while (i >= 0 && (type = getJoiningType(word[i])) == U_JT_TRANSPARENT)\n                {\n                    i--;\n                }\n                if (type == U_JT_DUAL_JOINING || type == U_JT_LEFT_JOINING || type == U_JT_JOIN_CAUSING)\n                {\n                    return HyphenationType.BREAK_AND_INSERT_HYPHEN_AND_ZWJ;\n                }\n            }\n            return HyphenationType.BREAK_AND_INSERT_HYPHEN;\n        }\n\n        public static readonly int kDirection_Mask = 0x1;\n\n        internal static uint disabledDecomposeCompatibility(hb_unicode_funcs_t UnnamedParameter, hb_codepoint_t UnnamedParameter2, hb_codepoint_t UnnamedParameter3, object UnnamedParameter4)\n        {\n            return 0;\n        }\n\n        public static android.hash_t hash_type(LayoutCacheKey key)\n        {\n            return key.hash();\n        }\n\n        internal static HarfBuzzSharp.Position harfbuzzGetGlyphHorizontalAdvance(HarfBuzzSharp.Font UnnamedParameter, object fontData, hb_codepoint_t glyph, object UnnamedParameter2)\n        {\n            //C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n            MinikinPaint paint = reinterpret_cast<MinikinPaint>(fontData);\n            float advance = paint.font.GetHorizontalAdvance(glyph, paint);\n            return 256 * advance + 0.5;\n        }\n\n        internal static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(HarfBuzzSharp.Font UnnamedParameter, object UnnamedParameter2, hb_codepoint_t UnnamedParameter3, HarfBuzzSharp.Position UnnamedParameter4, HarfBuzzSharp.Position UnnamedParameter5, object UnnamedParameter6)\n        {\n            // Just return true, following the way that Harfbuzz-FreeType\n            // implementation does.\n            return true;\n        }\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static hb_font_funcs_t getHbFontFuncs_hbFuncs = null;\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static hb_font_funcs_t getHbFontFuncs_hbFuncsForColorBitmap = null;\n\n        public static hb_font_funcs_t getHbFontFuncs(bool forColorBitmapFont)\n        {\n            assertMinikinLocked();\n\n            //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n            //  static hb_font_funcs_t* hbFuncs = null;\n            //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n            //  static hb_font_funcs_t* hbFuncsForColorBitmap = null;\n\n            hb_font_funcs_t[] funcs = forColorBitmapFont ? getHbFontFuncs_hbFuncs : getHbFontFuncs_hbFuncsForColorBitmap;\n            if (funcs[0] == null)\n            {\n                funcs[0] = hb_font_funcs_create();\n                if (forColorBitmapFont)\n                {\n                    // Don't override the h_advance function since we use HarfBuzz's\n                    // implementation for emoji for performance reasons. Note that it is\n                    // technically possible for a TrueType font to have outline and embedded\n                    // bitmap at the same time. We ignore modified advances of hinted outline\n                    // glyphs in that case.\n                }\n                else\n                {\n                    // Override the h_advance function since we can't use HarfBuzz's\n                    // implemenation. It may return the wrong value if the font uses hinting\n                    // aggressively.\n                    hb_font_funcs_set_glyph_h_advance_func(funcs[0], harfbuzzGetGlyphHorizontalAdvance, 0, 0);\n                }\n                hb_font_funcs_set_glyph_h_origin_func(funcs[0], harfbuzzGetGlyphHorizontalOrigin, 0, 0);\n                hb_font_funcs_make_immutablefuncs;\n            }\n            return funcs[0];\n        }\n\n        internal static bool isColorBitmapFont(HarfBuzzSharp.Font font)\n        {\n            HarfBuzzSharp.Face face = hb_font_get_face(font);\n            HbBlob cbdt = new HbBlob(hb_face_reference_table(face, HB_TAG('C', 'B', 'D', 'T')));\n            return cbdt.size() > 0;\n        }\n\n        internal static float HBFixedToFloat(HarfBuzzSharp.Position v)\n        {\n            return scalbnf(v, -8);\n        }\n\n        internal static HarfBuzzSharp.Position HBFloatToFixed(float v)\n        {\n            return scalbnf(v, +8);\n        }\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static hb_unicode_funcs_t codePointToScript_u = null;\n\n        internal static hb_script_t codePointToScript(hb_codepoint_t codepoint)\n        {\n            //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n            //  static hb_unicode_funcs_t* u = 0;\n            if (codePointToScript_u == null)\n            {\n                codePointToScript_u = LayoutEngine.getInstance().unicodeFunctions;\n            }\n            return hb_unicode_script(codePointToScript_u, codepoint);\n        }\n\n        internal static hb_codepoint_t decodeUtf16(UInt16[] chars, int len, ref uint iter)\n        {\n            UInt16 v = chars[iter++];\n            // test whether v in (0xd800..0xdfff), lead or trail surrogate\n            if ((v & 0xf800) == 0xd800)\n            {\n                // test whether v in (0xd800..0xdbff), lead surrogate\n                if (int(iter) < len && (v & 0xfc00) == 0xd800)\n                {\n                    UInt16 v2 = chars[iter++];\n                    // test whether v2 in (0xdc00..0xdfff), trail surrogate\n                    if ((v2 & 0xfc00) == 0xdc00)\n                    {\n                        // (0xd800 0xdc00) in utf-16 maps to 0x10000 in ucs-32\n                        hb_codepoint_t delta = (0xd800 << 10) + 0xdc00 - 0x10000;\n                        return (((hb_codepoint_t)v) << 10) + v2 - delta;\n                    }\n                    iter -= 1;\n                    return 0xFFFDu;\n                }\n                else\n                {\n                    return 0xFFFDu;\n                }\n            }\n            else\n            {\n                return v;\n            }\n        }\n\n        internal static hb_script_t getScriptRun(UInt16 chars, int len, ref uint iter)\n        {\n            if (iter == len)\n            {\n                return HB_SCRIPT_UNKNOWN;\n            }\n            uint cp = decodeUtf16(chars, len, ref iter);\n            hb_script_t current_script = codePointToScript(new uint(cp));\n            for (; ; )\n            {\n                if (iter == len)\n                {\n                    break;\n                }\n                uint prev_iter = iter;\n                cp = decodeUtf16(chars, len, ref iter);\n                hb_script_t script = codePointToScript(new uint(cp));\n                if (script != current_script)\n                {\n                    if (current_script == HB_SCRIPT_INHERITED || current_script == HB_SCRIPT_COMMON)\n                    {\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: current_script = script;\n                        current_script.CopyFrom(script);\n                    }\n                    else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON)\n                    {\n                        continue;\n                    }\n                    else\n                    {\n                        iter = prev_iter;\n                        break;\n                    }\n                }\n            }\n            if (current_script == HB_SCRIPT_INHERITED)\n            {\n                current_script = HB_SCRIPT_COMMON;\n            }\n\n            return current_script;\n        }\n\n        /**\n         * Disable certain scripts (mostly those with cursive connection) from having\n         * letterspacing applied. See https://github.com/behdad/harfbuzz/issues/64 for\n         * more details.\n         */\n        internal static bool isScriptOkForLetterspacing(hb_script_t script)\n        {\n            return !(script == HB_SCRIPT_ARABIC || script == HB_SCRIPT_NKO || script == HB_SCRIPT_PSALTER_PAHLAVI || script == HB_SCRIPT_MANDAIC || script == HB_SCRIPT_MONGOLIAN || script == HB_SCRIPT_PHAGS_PA || script == HB_SCRIPT_DEVANAGARI || script == HB_SCRIPT_BENGALI || script == HB_SCRIPT_GURMUKHI || script == HB_SCRIPT_MODI || script == HB_SCRIPT_SHARADA || script == HB_SCRIPT_SYLOTI_NAGRI || script == HB_SCRIPT_TIRHUTA || script == HB_SCRIPT_OGHAM);\n        }\n        //C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n        private static hb_feature_t addFeatures_feature = new hb_feature_t();\n\n        internal static void addFeatures(string str, vector<hb_feature_t> features)\n        {\n            if (str.Length == 0)\n            {\n                return;\n            }\n\n            //C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types:\n            //ORIGINAL LINE: const char* start = str.c_str();\n            char start = str;\n            //C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types:\n            //ORIGINAL LINE: const char* end = start + str.size();\n            char end = start + str.Length;\n\n            while (start < end)\n            {\n                //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n                //\tstatic hb_feature_t feature;\n                //C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types:\n                //ORIGINAL LINE: const char* p = strchr(start, ',');\n                char p = StringFunctions.StrChr(start, ',');\n                if (p == null)\n                {\n                    p = end;\n                }\n                /* We do not allow setting features on ranges.  As such, reject any\n                 * setting that has non-universal range. */\n                if (hb_feature_from_string(start, p - start, addFeatures_feature) && addFeatures_feature.start == 0 && addFeatures_feature.end == (uint)-1)\n                {\n                    features.push_back(addFeatures_feature);\n                }\n                start = p + 1;\n            }\n        }\n\n        internal const hb_codepoint_t CHAR_HYPHEN = 0x2010; // HYPHEN\n\n        internal static hb_codepoint_t determineHyphenChar(hb_codepoint_t preferredHyphen, HarfBuzzSharp.Font font)\n        {\n            hb_codepoint_t glyph = new hb_codepoint_t();\n            if (preferredHyphen == 0x058A || preferredHyphen == 0x05BE || preferredHyphen == 0x1400)\n            {\n                if (hb_font_get_nominal_glyph(font, preferredHyphen, glyph))\n                {\n                    return preferredHyphen;\n                }\n                else\n                {\n                    // The original hyphen requested was not supported. Let's try and see if\n                    // the Unicode hyphen is supported.\n                    preferredHyphen = CHAR_HYPHEN;\n                }\n            }\n            if (preferredHyphen == CHAR_HYPHEN)\n            { // HYPHEN\n              // Fallback to ASCII HYPHEN-MINUS if the font didn't have a glyph for the\n              // preferred hyphen. Note that we intentionally don't do anything special if\n              // the font doesn't have a HYPHEN-MINUS either, so a tofu could be shown,\n              // hinting towards something missing.\n                if (!hb_font_get_nominal_glyph(font, preferredHyphen, glyph))\n                {\n                    return 0x002D; // HYPHEN-MINUS\n                }\n            }\n            return preferredHyphen;\n        }\n\n        internal static void addHyphenToHbBuffer(hb_buffer_t buffer, HarfBuzzSharp.Font font, uint hyphen, uint cluster)\n        {\n            //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged:\n            uint* hyphenStr = HyphenEdit.getHyphenString(hyphen);\n            while (*hyphenStr != 0)\n            {\n                hb_codepoint_t hyphenChar = determineHyphenChar(*hyphenStr, font);\n                hb_buffer_add(buffer, hyphenChar, cluster);\n                hyphenStr++;\n            }\n        }\n\n        // Returns the cluster value assigned to the first codepoint added to the\n        // buffer, which can be used to translate cluster values returned by HarfBuzz to\n        // input indices.\n        internal static uint addToHbBuffer(hb_buffer_t buffer, UInt16 buf, int start, int count, int bufSize, uint scriptRunStart, uint scriptRunEnd, HyphenEdit hyphenEdit, HarfBuzzSharp.Font hbFont)\n        {\n            // Only hyphenate the very first script run for starting hyphens.\n            uint startHyphen = (scriptRunStart == 0) ? hyphenEdit.getStart() : HyphenEdit.NO_EDIT;\n            // Only hyphenate the very last script run for ending hyphens.\n            uint endHyphen = ((int)scriptRunEnd == count) != null ? hyphenEdit.getEnd() : HyphenEdit.NO_EDIT;\n\n            // In the following code, we drop the pre-context and/or post-context if there\n            // is a hyphen edit at that end. This is not absolutely necessary, since\n            // HarfBuzz uses contexts only for joining scripts at the moment, e.g. to\n            // determine if the first or last letter of a text range to shape should take\n            // a joining form based on an adjacent letter or joiner (that comes from the\n            // context).\n            //\n            // TODO: Revisit this for:\n            // 1. Desperate breaks for joining scripts like Arabic (where it may be better\n            // to keep\n            //    the context);\n            // 2. Special features like start-of-word font features (not implemented in\n            // HarfBuzz\n            //    yet).\n\n            // We don't have any start-of-line replacement edit yet, so we don't need to\n            // check for those.\n            if (HyphenEdit.isInsertion(startHyphen))\n            {\n                // A cluster value of zero guarantees that the inserted hyphen will be in\n                // the same cluster with the next codepoint, since there is no pre-context.\n                addHyphenToHbBuffer(buffer, hbFont, new uint(startHyphen), 0);\n            }\n\n            UInt16 hbText;\n            int hbTextLength;\n            uint hbItemOffset;\n            uint hbItemLength = scriptRunEnd - scriptRunStart; // This is >= 1.\n\n            bool hasEndInsertion = HyphenEdit.isInsertion(endHyphen);\n            bool hasEndReplacement = HyphenEdit.isReplacement(endHyphen);\n            if (hasEndReplacement)\n            {\n                // Skip the last code unit while copying the buffer for HarfBuzz if it's a\n                // replacement. We don't need to worry about non-BMP characters yet since\n                // replacements are only done for code units at the moment.\n                hbItemLength -= 1;\n            }\n\n            if (startHyphen == HyphenEdit.NO_EDIT)\n            {\n                // No edit at the beginning. Use the whole pre-context.\n                hbText = buf;\n                hbItemOffset = start + scriptRunStart;\n            }\n            else\n            {\n                // There's an edit at the beginning. Drop the pre-context and start the\n                // buffer at where we want to start shaping.\n                hbText = buf + start + scriptRunStart;\n                hbItemOffset = 0;\n            }\n\n            if (endHyphen == HyphenEdit.NO_EDIT)\n            {\n                // No edit at the end, use the whole post-context.\n                hbTextLength = (buf + bufSize) - hbText;\n            }\n            else\n            {\n                // There is an edit at the end. Drop the post-context.\n                hbTextLength = hbItemOffset + hbItemLength;\n            }\n\n            hb_buffer_add_utf16(buffer, hbText, hbTextLength, hbItemOffset, hbItemLength);\n\n            uint numCodepoints;\n            hb_glyph_info_t[] cpInfo = hb_buffer_get_glyph_infos(buffer, numCodepoints);\n\n            // Add the hyphen at the end, if there's any.\n            if (hasEndInsertion || hasEndReplacement)\n            {\n                // When a hyphen is inserted, by assigning the added hyphen and the last\n                // codepoint added to the HarfBuzz buffer to the same cluster, we can make\n                // sure that they always remain in the same cluster, even if the last\n                // codepoint gets merged into another cluster (for example when it's a\n                // combining mark).\n                //\n                // When a replacement happens instead, we want it to get the cluster value\n                // of the character it's replacing, which is one \"codepoint length\" larger\n                // than the last cluster. But since the character replaced is always just\n                // one code unit, we can just add 1.\n                uint hyphenCluster = new uint();\n                if (numCodepoints == 0)\n                {\n                    // Nothing was added to the HarfBuzz buffer. This can only happen if\n                    // we have a replacement that is replacing a one-code unit script run.\n                    hyphenCluster = 0;\n                }\n                else\n                {\n                    hyphenCluster = cpInfo[numCodepoints - 1].cluster + (uint)hasEndReplacement;\n                }\n                addHyphenToHbBuffer(buffer, hbFont, new uint(endHyphen), new uint(hyphenCluster));\n                // Since we have just added to the buffer, cpInfo no longer necessarily\n                // points to the right place. Refresh it.\n                cpInfo = hb_buffer_get_glyph_infos(buffer, null);\n            }\n            return cpInfo[0].cluster;\n        }\n\n        /*\n         * Determine whether the code unit is a word space for the purposes of\n         * justification.\n         */\n\n        /*\n         * Determine whether the code unit is a word space for the purposes of\n         * justification.\n         */\n        public static bool isWordSpace(UInt16 code_unit)\n        {\n            return code_unit == ' ' || code_unit == CHAR_NBSP;\n        }\n\n        /**\n         * Return offset of previous word break. It is either < offset or == 0.\n         */\n\n        /**\n         * Return offset of previous word break. It is either < offset or == 0.\n         *\n         * For the purpose of layout, a word break is a boundary with no\n         * kerning or complex script processing. This is necessarily a\n         * heuristic, but should be accurate most of the time.\n         */\n        public static int getPrevWordBreakForCache(UInt16[] chars, int offset, int len)\n        {\n            if (offset == 0)\n            {\n                return 0;\n            }\n            if (offset > len)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: offset = len;\n                offset.CopyFrom(len);\n            }\n            if (isWordBreakBefore(chars[offset - 1]))\n            {\n                return offset - 1;\n            }\n            for (int i = offset - 1; i > 0; i--)\n            {\n                if (isWordBreakBefore(chars[i]) || isWordBreakAfter(chars[i - 1]))\n                {\n                    return i;\n                }\n            }\n            return 0;\n        }\n\n        /**\n         * Return offset of next word break. It is either > offset or == len.\n         */\n\n        /**\n         * Return offset of next word break. It is either > offset or == len.\n         *\n         * For the purpose of layout, a word break is a boundary with no\n         * kerning or complex script processing. This is necessarily a\n         * heuristic, but should be accurate most of the time.\n         */\n        public static int getNextWordBreakForCache(UInt16[] chars, int offset, int len)\n        {\n            if (offset >= len)\n            {\n                return len;\n            }\n            if (isWordBreakAfter(chars[offset]))\n            {\n                return offset + 1;\n            }\n            for (int i = offset + 1; i < len; i++)\n            {\n                // No need to check isWordBreakAfter(chars[i - 1]) since it is checked\n                // in previous iteration.  Note that isWordBreakBefore returns true\n                // whenever isWordBreakAfter returns true.\n                if (isWordBreakBefore(chars[i]))\n                {\n                    return i;\n                }\n            }\n            return len;\n        }\n\n        public static readonly UInt16 CHAR_NBSP = 0x00A0;\n\n        /**\n         * For the purpose of layout, a word break is a boundary with no\n         * kerning or complex script processing. This is necessarily a\n         * heuristic, but should be accurate most of the time.\n         */\n        internal static bool isWordBreakAfter(UInt16 c)\n        {\n            if (isWordSpace(new UInt16(c)) || (c >= 0x2000 && c <= 0x200a) || c == 0x3000)\n            {\n                // spaces\n                return true;\n            }\n            // Note: kana is not included, as sophisticated fonts may kern kana\n            return false;\n        }\n\n        internal static bool isWordBreakBefore(UInt16 c)\n        {\n            // CJK ideographs (and yijing hexagram symbols)\n            return isWordBreakAfter(new UInt16(c)) || (c >= 0x3400 && c <= 0x9fff);\n        }\n\n        public static readonly int CHAR_TAB = 0x0009;\n\n        // Large scores in a hierarchy; we prefer desperate breaks to an overfull line.\n        // All these constants are larger than any reasonable actual width score.\n        public static readonly float SCORE_INFTY = float.MaxValue;\n        public static readonly float SCORE_OVERFULL = 1e12f;\n        public static readonly float SCORE_DESPERATE = 1e10f;\n\n        // Multiplier for hyphen penalty on last line.\n        public static readonly float LAST_LINE_PENALTY_MULTIPLIER = 4.0f;\n        // Penalty assigned to each line break (to try to minimize number of lines)\n        // TODO: when we implement full justification (so spaces can shrink and\n        // stretch), this is probably not the most appropriate method.\n        public static readonly float LINE_PENALTY_MULTIPLIER = 2.0f;\n\n        // Penalty assigned to shrinking the whitepsace.\n        public static readonly float SHRINK_PENALTY_MULTIPLIER = 4.0f;\n\n        // Very long words trigger O(n^2) behavior in hyphenation, so we disable\n        // hyphenation for unreasonably long words. This is somewhat of a heuristic\n        // because extremely long words are possible in some languages. This does mean\n        // that very long real words can get broken by desperate breaks, with no\n        // hyphens.\n        public static readonly int LONGEST_HYPHENATED_WORD = 45;\n\n        // When the text buffer is within this limit, capacity of vectors is retained at\n        // finish(), to avoid allocation.\n        public static readonly int MAX_TEXT_BUF_RETAIN = 32678;\n\n        // Maximum amount that spaces can shrink, in justified text.\n        public static readonly float SHRINKABILITY = 1.0 / 3.0;\n\n        // This function determines whether a character is a space that disappears at\n        // end of line. It is the Unicode set:\n        // [[:General_Category=Space_Separator:]-[:Line_Break=Glue:]], plus '\\n'. Note:\n        // all such characters are in the BMP, so it's ok to use code units for this.\n        public static bool isLineEndSpace(UInt16 c)\n        {\n            return c == '\\n' || c == ' ' || c == 0x1680 || (0x2000 <= c != null && c <= 0x200A && c != 0x2007) || c == 0x205F || c == 0x3000;\n        }\n\n        // These could be considered helper methods of layout, but need only be loosely\n        // coupled, so are separate.\n\n        internal static float getRunAdvance(float[] advances, UInt16 buf, int layoutStart, int start, int count, int offset)\n        {\n            float advance = 0.0f;\n            int lastCluster = start;\n            float clusterWidth = 0.0f;\n            for (int i = start; i < offset; i++)\n            {\n                float charAdvance = advances[i - layoutStart];\n                if (charAdvance != 0.0f)\n                {\n                    advance += charAdvance;\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: lastCluster = i;\n                    lastCluster.CopyFrom(i);\n                    clusterWidth = charAdvance;\n                }\n            }\n            if (offset < start + count && advances[offset - layoutStart] == 0.0f)\n            {\n                // In the middle of a cluster, distribute width of cluster so that each\n                // grapheme cluster gets an equal share.\n                // TODO: get caret information out of font when that's available\n                int nextCluster = new int();\n                for (nextCluster = offset + 1; nextCluster < start + count; nextCluster++)\n                {\n                    if (advances[nextCluster - layoutStart] != 0.0f)\n                    {\n                        break;\n                    }\n                }\n                int numGraphemeClusters = 0;\n                int numGraphemeClustersAfter = 0;\n                for (int i = lastCluster; i < nextCluster; i++)\n                {\n                    bool isAfter = i >= offset;\n                    if (GraphemeBreak.isGraphemeBreak(advances + (start - layoutStart), buf, start, count, i))\n                    {\n                        numGraphemeClusters++;\n                        if (isAfter)\n                        {\n                            numGraphemeClustersAfter++;\n                        }\n                    }\n                }\n                if (numGraphemeClusters > 0)\n                {\n                    advance -= clusterWidth * numGraphemeClustersAfter / numGraphemeClusters;\n                }\n            }\n            return advance;\n        }\n\n        public static float getRunAdvance(float advances, UInt16 buf, int start, int count, int offset)\n        {\n            return getRunAdvance(advances, buf, start, start, count, offset);\n        }\n\n        /**\n         * Essentially the inverse of getRunAdvance. Compute the value of offset for\n         * which the measured caret comes closest to the provided advance param, and\n         * which is on a grapheme cluster boundary.\n         *\n         * The actual implementation fast-forwards through clusters to get \"close\", then\n         * does a finer-grain search within the cluster and grapheme breaks.\n         */\n        public static int getOffsetForAdvance(float[] advances, UInt16 buf, int start, int count, float advance)\n        {\n            float x = 0.0f;\n            float xLastClusterStart = 0.0f;\n            float xSearchStart = 0.0f;\n            int lastClusterStart = start;\n            int searchStart = start;\n            for (int i = start; i < start + count; i++)\n            {\n                if (GraphemeBreak.isGraphemeBreak(advances, buf, start, count, i))\n                {\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: searchStart = lastClusterStart;\n                    searchStart.CopyFrom(lastClusterStart);\n                    xSearchStart = xLastClusterStart;\n                }\n                float width = advances[i - start];\n                if (width != 0.0f)\n                {\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: lastClusterStart = i;\n                    lastClusterStart.CopyFrom(i);\n                    xLastClusterStart = x;\n                    x += width;\n                    if (x > advance)\n                    {\n                        break;\n                    }\n                }\n            }\n            int best = searchStart;\n            float bestDist = FLT_MAX;\n            for (int i = searchStart; i <= start + count; i++)\n            {\n                if (GraphemeBreak.isGraphemeBreak(advances, buf, start, count, i))\n                {\n                    // \"getRunAdvance(layout, buf, start, count, i) - advance\" but more\n                    // efficient\n                    float delta = getRunAdvance(advances, buf, start, searchStart, count - searchStart, i) + xSearchStart - advance;\n                    if (Math.Abs(delta) < bestDist)\n                    {\n                        bestDist = Math.Abs(delta);\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: best = i;\n                        best.CopyFrom(i);\n                    }\n                    if (delta >= 0.0f)\n                    {\n                        break;\n                    }\n                }\n            }\n            return best;\n        }\n\n        // All external Minikin interfaces are designed to be thread-safe.\n        // Presently, that's implemented by through a global lock, and having\n        // all external interfaces take that lock.\n\n        //C++ TO C# CONVERTER NOTE: 'extern' variable declarations are not required in C#:\n        //extern std::recursive_mutex gMinikinLock;\n\n        // Aborts if gMinikinLock is not acquired. Do nothing on the release build.\n        public static void assertMinikinLocked()\n        {\n#if ENABLE_RACE_DETECTION\n\t  LOG_ALWAYS_FATAL_IF(gMinikinLock.tryLock() == 0);\n#endif\n        }\n\n        public static hb_blob_t getFontTable(MinikinFont minikinFont, uint tag)\n        {\n            assertMinikinLocked();\n            HarfBuzzSharp.Font font = getHbFontLocked(minikinFont);\n            HarfBuzzSharp.Face face = hb_font_get_face(font);\n            hb_blob_t blob = hb_face_reference_table(face, tag);\n            hb_font_destroy(font);\n            return blob;\n        }\n\n        public const uint MAX_UNICODE_CODE_POINT = 0x10FFFF;\n\n        public static std::recursive_mutex gMinikinLock = new std::recursive_mutex();\n\n        public static readonly uint SparseBitSet.kNotFound = new uint ();\n\n\tpublic static readonly uint CHAR_SOFT_HYPHEN = 0x00AD;\n        public static readonly uint CHAR_ZWJ = 0x200D;\n\n        /**\n         * Determine whether a line break at position i within the buffer buf is valid.\n         *This represents customization beyond the ICU behavior, because plain ICU\n         *provides some line break opportunities that we don't want.\n         **/\n        internal static bool isBreakValid(UInt16 buf, int bufEnd, int i)\n        {\n            uint codePoint = new uint();\n            int prev_offset = i;\n            U16_PREV(buf, 0, prev_offset, codePoint);\n            // Do not break on hard or soft hyphens. These are handled by automatic\n            // hyphenation.\n            if (Hyphenator.isLineBreakingHyphen(codePoint) || codePoint == CHAR_SOFT_HYPHEN)\n            {\n                // txt addition: Temporarily always break on hyphen. Changed from false to\n                // true.\n                return true;\n            }\n            // For Myanmar kinzi sequences, created by <consonant, ASAT, VIRAMA,\n            // consonant>. This is to go around a bug in ICU line breaking:\n            // http://bugs.icu-project.org/trac/ticket/12561. To avoid too much looking\n            // around in the strings, we simply avoid breaking after any Myanmar virama,\n            // where no line break could be imagined, since the Myanmar virama is a pure\n            // stacker.\n            if (codePoint == 0x1039)\n            { // MYANMAR SIGN VIRAMA\n                return false;\n            }\n\n            uint next_codepoint = new uint();\n            int next_offset = i;\n            U16_NEXT(buf, next_offset, bufEnd, next_codepoint);\n\n            // Rule LB8 for Emoji ZWJ sequences. We need to do this ourselves since we may\n            // have fresher emoji data than ICU does.\n            if (codePoint == CHAR_ZWJ && isEmoji(next_codepoint))\n            {\n                return false;\n            }\n\n            // Rule LB30b. We need to this ourselves since we may have fresher emoji data\n            // than ICU does.\n            if (isEmojiModifier(next_codepoint))\n            {\n                if (codePoint == 0xFE0F && prev_offset > 0)\n                {\n                    // skip over emoji variation selector\n                    U16_PREV(buf, 0, prev_offset, codePoint);\n                }\n                if (isEmojiBase(codePoint))\n                {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        // Chicago Manual of Style recommends breaking after these characters in URLs\n        // and email addresses\n        internal static bool breakAfter(UInt16 c)\n        {\n            return c == ':' || c == '=' || c == '&';\n        }\n\n        // Chicago Manual of Style recommends breaking before these characters in URLs\n        // and email addresses\n        internal static bool breakBefore(UInt16 c)\n        {\n            return c == '~' || c == '.' || c == ',' || c == '-' || c == '_' || c == '?' || c == '#' || c == '%' || c == '=' || c == '&';\n        }\n\n        // Returns true if c is emoji.\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //bool isEmoji(uint c);\n\n        // Returns true if c is emoji modifier base.\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //bool isEmojiBase(uint c);\n\n        // Returns true if c is emoji modifier.\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //bool isEmojiModifier(uint c);\n\n        // Bidi override for ICU that knows about new emoji.\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //UCharDirection emojiBidiOverride(object context, UChar32 c);\n\n        public static android.hash_t hash_type(FontStyle style)\n        {\n            return style.hash();\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //bool isLineEndSpace(UInt16 c);\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //float getRunAdvance(float advances, UInt16 buf, int start, int count, int offset);\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //int getOffsetForAdvance(float advances, UInt16 buf, int start, int count, float advance);\n    }\n}"
  },
  {
    "path": "FlutterBinding/Minikin/GraphemeBreak.cs",
    "content": "﻿using System;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/GraphemeBreak.h.cs",
    "content": "﻿/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\nnamespace minikin\n{\n\npublic class GraphemeBreak\n{\n  // These values must be kept in sync with CURSOR_AFTER etc in Paint.java\n  public enum MoveOpt\n  {\n\tAFTER = 0,\n\tAT_OR_AFTER = 1,\n\tBEFORE = 2,\n\tAT_OR_BEFORE = 3,\n\tAT = 4\n  }\n\n  // Determine whether the given offset is a grapheme break.\n  // This implementation generally follows Unicode's UTR #29 extended\n  // grapheme break, with various tweaks.\n\tpublic bool isGraphemeBreak(float[] advances, UInt16[] buf, int start, int count, int offset)\n\t{\n\t  // This implementation closely follows Unicode Standard Annex #29 on\n\t  // Unicode Text Segmentation (http://www.unicode.org/reports/tr29/),\n\t  // implementing a tailored version of extended grapheme clusters.\n\t  // The GB rules refer to section 3.1.1, Grapheme Cluster Boundary Rules.\n    \n\t  // Rule GB1, sot ÷; Rule GB2, ÷ eot\n\t  if (offset <= start != null || offset >= start + count)\n\t  {\n\t\treturn true;\n\t  }\n\t  if (U16_IS_TRAIL(buf[offset]))\n\t  {\n\t\t// Don't break a surrogate pair, but a lonely trailing surrogate pair is a\n\t\t// break\n\t\treturn !U16_IS_LEAD(buf[offset - 1]);\n\t  }\n\t  uint c1 = 0;\n\t  uint c2 = 0;\n\t  int offset_back = offset;\n\t  int offset_forward = offset;\n\t  U16_PREV(buf, start, offset_back, c1);\n\t  U16_NEXT(buf, offset_forward, start + count, c2);\n\t  int p1 = tailoredGraphemeClusterBreak(new uint(c1));\n\t  int p2 = tailoredGraphemeClusterBreak(new uint(c2));\n\t  // Rule GB3, CR x LF\n\t  if (p1 == U_GCB_CR && p2 == U_GCB_LF)\n\t  {\n\t\treturn false;\n\t  }\n\t  // Rule GB4, (Control | CR | LF) ÷\n\t  if (p1 == U_GCB_CONTROL || p1 == U_GCB_CR || p1 == U_GCB_LF)\n\t  {\n\t\treturn true;\n\t  }\n\t  // Rule GB5, ÷ (Control | CR | LF)\n\t  if (p2 == U_GCB_CONTROL || p2 == U_GCB_CR || p2 == U_GCB_LF)\n\t  {\n\t\treturn true;\n\t  }\n\t  // Rule GB6, L x ( L | V | LV | LVT )\n\t  if (p1 == U_GCB_L && (p2 == U_GCB_L || p2 == U_GCB_V || p2 == U_GCB_LV || p2 == U_GCB_LVT))\n\t  {\n\t\treturn false;\n\t  }\n\t  // Rule GB7, ( LV | V ) x ( V | T )\n\t  if ((p1 == U_GCB_LV || p1 == U_GCB_V) && (p2 == U_GCB_V || p2 == U_GCB_T))\n\t  {\n\t\treturn false;\n\t  }\n\t  // Rule GB8, ( LVT | T ) x T\n\t  if ((p1 == U_GCB_LVT || p1 == U_GCB_T) && p2 == U_GCB_T)\n\t  {\n\t\treturn false;\n\t  }\n\t  // Rule GB9, x (Extend | ZWJ); Rule GB9a, x SpacingMark; Rule GB9b, Prepend x\n\t  if (p2 == U_GCB_EXTEND || p2 == U_GCB_ZWJ || p2 == U_GCB_SPACING_MARK || p1 == U_GCB_PREPEND)\n\t  {\n\t\treturn false;\n\t  }\n    \n\t  // This is used to decide font-dependent grapheme clusters. If we don't have\n\t  // the advance information, we become conservative in grapheme breaking and\n\t  // assume that it has no advance.\n\t  bool c2_has_advance = (advances != null && advances[offset - start] != 0.0);\n    \n\t  // All the following rules are font-dependent, in the way that if we know c2\n\t  // has an advance, we definitely know that it cannot form a grapheme with the\n\t  // character(s) before it. So we make the decision in favor a grapheme break\n\t  // early.\n\t  if (c2_has_advance)\n\t  {\n\t\treturn true;\n\t  }\n    \n\t  // Note: For Rule GB10 and GB11 below, we do not use the Unicode line breaking\n\t  // properties for determining emoji-ness and carry our own data, because our\n\t  // data could be more fresh than what ICU provides.\n\t  //\n\t  // Tailored version of Rule GB10, (E_Base | EBG) Extend* × E_Modifier.\n\t  // The rule itself says do not break between emoji base and emoji modifiers,\n\t  // skipping all Extend characters. Variation selectors are considered Extend,\n\t  // so they are handled fine.\n\t  //\n\t  // We tailor this by requiring that an actual ligature is formed. If the font\n\t  // doesn't form a ligature, we allow a break before the modifier.\n\t  if (isEmojiModifier(c2))\n\t  {\n\t\tuint c0 = new uint(c1);\n\t\tint offset_backback = offset_back;\n\t\tint p0 = p1;\n\t\tif (p0 == U_GCB_EXTEND && offset_backback > start)\n\t\t{\n\t\t  // skip over emoji variation selector\n\t\t  U16_PREV(buf, start, offset_backback, c0);\n\t\t  p0 = tailoredGraphemeClusterBreak(new uint(c0));\n\t\t}\n\t\tif (isEmojiBase(c0))\n\t\t{\n\t\t  return false;\n\t\t}\n\t  }\n    \n\t  // Tailored version of Rule GB11, ZWJ × (Glue_After_Zwj | EBG)\n\t  // We try to make emoji sequences with ZWJ a single grapheme cluster, but only\n\t  // if they actually merge to one cluster. So we are more relaxed than the UAX\n\t  // #29 rules in accepting any emoji character after the ZWJ, but are tighter\n\t  // in that we only treat it as one cluster if a ligature is actually formed\n\t  // and we also require the character before the ZWJ to also be an emoji.\n\t  if (p1 == U_GCB_ZWJ && isEmoji(c2) && offset_back > start)\n\t  {\n\t\t// look at character before ZWJ to see that both can participate in an\n\t\t// emoji zwj sequence\n\t\tuint c0 = 0;\n\t\tint offset_backback = offset_back;\n\t\tU16_PREV(buf, start, offset_backback, c0);\n\t\tif (c0 == 0xFE0F && offset_backback > start)\n\t\t{\n\t\t  // skip over emoji variation selector\n\t\t  U16_PREV(buf, start, offset_backback, c0);\n\t\t}\n\t\tif (isEmoji(c0))\n\t\t{\n\t\t  return false;\n\t\t}\n\t  }\n    \n\t  // Tailored version of Rule GB12 and Rule GB13 that look at even-odd cases.\n\t  // sot   (RI RI)*  RI x RI\n\t  // [^RI] (RI RI)*  RI x RI\n\t  //\n\t  // If we have font information, we have already broken the cluster if and only\n\t  // if the second character had no advance, which means a ligature was formed.\n\t  // If we don't, we look back like UAX #29 recommends, but only up to 1000 code\n\t  // units.\n\t  if (p1 == U_GCB_REGIONAL_INDICATOR && p2 == U_GCB_REGIONAL_INDICATOR)\n\t  {\n\t\tif (advances != null)\n\t\t{\n\t\t  // We have advances information. But if we are here, we already know c2\n\t\t  // has no advance. So we should definitely disallow a break.\n\t\t  return false;\n\t\t}\n\t\telse\n\t\t{\n\t\t  // Look at up to 1000 code units.\n\t\t  int lookback_barrier = Math.Max((IntPtr)start, (IntPtr)offset_back - 1000);\n\t\t  int offset_backback = offset_back;\n\t\t  while (offset_backback > lookback_barrier)\n\t\t  {\n\t\t\tuint c0 = 0;\n\t\t\tU16_PREV(buf, lookback_barrier, offset_backback, c0);\n\t\t\tif (tailoredGraphemeClusterBreak(new uint(c0)) != U_GCB_REGIONAL_INDICATOR)\n\t\t\t{\n\t\t\t  offset_backback += U16_LENGTH(c0);\n\t\t\t  break;\n\t\t\t}\n\t\t  }\n\t\t  // The number 4 comes from the number of code units in a whole flag.\n\t\t  return (offset - offset_backback) % 4 == 0;\n\t\t}\n\t  }\n\t  // Cluster Indic syllables together (tailoring of UAX #29).\n\t  // Immediately after each virama (that is not just a pure killer) followed by\n\t  // a letter, we disallow grapheme breaks (if we are here, we don't know about\n\t  // advances, or we already know that c2 has no advance).\n\t  if (u_getIntPropertyValue(c1, UCHAR_CANONICAL_COMBINING_CLASS) == 9 && !isPureKiller(new uint(c1)) && u_getIntPropertyValue(c2, UCHAR_GENERAL_CATEGORY) == U_OTHER_LETTER)\n\t  {\n\t\treturn false;\n\t  }\n\t  // Rule GB999, Any ÷ Any\n\t  return true;\n\t}\n\n  // Matches Android's Java API. Note, return (int)-1 for AT to\n  // signal non-break because unsigned return type.\n\tpublic int getTextRunCursor(float advances, UInt16 buf, int start, int count, int offset, MoveOpt opt)\n\t{\n\t  switch (opt)\n\t  {\n\t\tcase AFTER:\n\t\t  if (offset < start + count)\n\t\t  {\n\t\t\toffset++;\n\t\t  }\n\t\t  // fall through\n\t//C++ TO C# CONVERTER TODO TASK: C# does not allow fall-through from a non-empty 'case':\n\t\tcase AT_OR_AFTER:\n\t\t  while (!isGraphemeBreak(advances, buf, start, count, offset))\n\t\t  {\n\t\t\toffset++;\n\t\t  }\n\t\t  break;\n\t\tcase BEFORE:\n\t\t  if (offset > start)\n\t\t  {\n\t\t\toffset--;\n\t\t  }\n\t\t  // fall through\n\t//C++ TO C# CONVERTER TODO TASK: C# does not allow fall-through from a non-empty 'case':\n\t\tcase AT_OR_BEFORE:\n\t\t  while (!isGraphemeBreak(advances, buf, start, count, offset))\n\t\t  {\n\t\t\toffset--;\n\t\t  }\n\t\t  break;\n\t\tcase AT:\n\t\t  if (!isGraphemeBreak(advances, buf, start, count, offset))\n\t\t  {\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: offset = (int)-1;\n\t\t\toffset.CopyFrom((int) - 1);\n\t\t  }\n\t\t  break;\n\t  }\n\t  return offset;\n\t}\n}\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/HbFontCache.cs",
    "content": "﻿/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n//C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n//struct HarfBuzzSharp.Font;\n\nnamespace minikin\n{\n//C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n//class MinikinFont;\n\n} // namespace minikin\n\n\n\n\n\nnamespace minikin\n{\n\n//C++ TO C# CONVERTER TODO TASK: C# has no concept of 'private' inheritance:\n//ORIGINAL LINE: class HbFontCache : private android::OnEntryRemoved<int, HarfBuzzSharp.Font*>\npublic class HbFontCache : android.OnEntryRemoved<int, HarfBuzzSharp.Font*>\n{\n  public HbFontCache()\n  {\n\t  this.mCache = kMaxEntries;\n\tmCache.setOnEntryRemovedListener(this.functorMethod);\n  }\n\n  // callback for OnEntryRemoved\n  public static void functorMethod(int UnnamedParameter, ref HarfBuzzSharp.Font value)\n  {\n\thb_font_destroy(value);\n  }\n\n  public HarfBuzzSharp.Font get(int fontId)\n  {\n\t  return mCache.get(fontId);\n  }\n\n  public void put(int fontId, HarfBuzzSharp.Font font)\n  {\n\t  mCache.put(fontId, font);\n  }\n\n  public void clear()\n  {\n\t  mCache.clear();\n  }\n\n  public void remove(int fontId)\n  {\n\t  mCache.remove(fontId);\n  }\n\n  private const int kMaxEntries = 100;\n\n  private android.LruCache<int, HarfBuzzSharp.Font> mCache = new android.LruCache<int, HarfBuzzSharp.Font>();\n}\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/Hyphenator.cs",
    "content": "﻿using System;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n// HACK: for reading pattern file\n\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * An implementation of Liang's hyphenation algorithm.\n */\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/locid.h\"\n\n\nnamespace minikin\n{\n\npublic enum HyphenationType : byte\n{\n  // Note: There are implicit assumptions scattered in the code that DONT_BREAK\n  // is 0.\n\n  // Do not break.\n  DONT_BREAK = 0,\n  // Break the line and insert a normal hyphen.\n  BREAK_AND_INSERT_HYPHEN = 1,\n  // Break the line and insert an Armenian hyphen (U+058A).\n  BREAK_AND_INSERT_ARMENIAN_HYPHEN = 2,\n  // Break the line and insert a maqaf (Hebrew hyphen, U+05BE).\n  BREAK_AND_INSERT_MAQAF = 3,\n  // Break the line and insert a Canadian Syllabics hyphen (U+1400).\n  BREAK_AND_INSERT_UCAS_HYPHEN = 4,\n  // Break the line, but don't insert a hyphen. Used for cases when there is\n  // already a hyphen\n  // present or the script does not use a hyphen (e.g. in Malayalam).\n  BREAK_AND_DONT_INSERT_HYPHEN = 5,\n  // Break and replace the last code unit with hyphen. Used for Catalan \"l·l\"\n  // which hyphenates\n  // as \"l-/l\".\n  BREAK_AND_REPLACE_WITH_HYPHEN = 6,\n  // Break the line, and repeat the hyphen (which is the last character) at the\n  // beginning of the\n  // next line. Used in Polish, where \"czerwono-niebieska\" should hyphenate as\n  // \"czerwono-/-niebieska\".\n  BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE = 7,\n  // Break the line, insert a ZWJ and hyphen at the first line, and a ZWJ at the\n  // second line.\n  // This is used in Arabic script, mostly for writing systems of Central Asia.\n  // It's our default\n  // behavior when a soft hyphen is used in Arabic script.\n  BREAK_AND_INSERT_HYPHEN_AND_ZWJ = 8\n}\n\n// The hyphen edit represents an edit to the string when a word is\n// hyphenated. The most common hyphen edit is adding a \"-\" at the end\n// of a syllable, but nonstandard hyphenation allows for more choices.\n// Note that a HyphenEdit can hold two types of edits at the same time,\n// One at the beginning of the string/line and one at the end.\npublic class HyphenEdit\n{\n  public const uint NO_EDIT = 0x00;\n\n  public const uint INSERT_HYPHEN_AT_END = 0x01;\n  public const uint INSERT_ARMENIAN_HYPHEN_AT_END = 0x02;\n  public const uint INSERT_MAQAF_AT_END = 0x03;\n  public const uint INSERT_UCAS_HYPHEN_AT_END = 0x04;\n  public const uint INSERT_ZWJ_AND_HYPHEN_AT_END = 0x05;\n  public const uint REPLACE_WITH_HYPHEN_AT_END = 0x06;\n  public const uint BREAK_AT_END = 0x07;\n\n  public uint INSERT_HYPHEN_AT_START = 0x01 << 3;\n  public uint INSERT_ZWJ_AT_START = 0x02 << 3;\n  public uint BREAK_AT_START = 0x03 << 3;\n\n  // Keep in sync with the definitions in the Java code at:\n  // frameworks/base/graphics/java/android/graphics/Paint.java\n  public const uint MASK_END_OF_LINE = 0x07;\n  public uint MASK_START_OF_LINE = 0x03 << 3;\n\n  public static bool isReplacement(uint hyph)\n  {\n\treturn hyph == REPLACE_WITH_HYPHEN_AT_END;\n  }\n\n  public static bool isInsertion(uint hyph)\n  {\n\treturn (hyph == INSERT_HYPHEN_AT_END || hyph == INSERT_ARMENIAN_HYPHEN_AT_END || hyph == INSERT_MAQAF_AT_END || hyph == INSERT_UCAS_HYPHEN_AT_END || hyph == INSERT_ZWJ_AND_HYPHEN_AT_END || hyph == INSERT_HYPHEN_AT_START || hyph == INSERT_ZWJ_AT_START);\n  }\n\n  public static uint getHyphenString(uint hyph)\n  {\n\tswitch (hyph)\n\t{\n\t  case INSERT_HYPHEN_AT_END:\n\t  case REPLACE_WITH_HYPHEN_AT_END:\n\t  case INSERT_HYPHEN_AT_START:\n\t\treturn GlobalMembers.HYPHEN_STR;\n\t  case INSERT_ARMENIAN_HYPHEN_AT_END:\n\t\treturn GlobalMembers.ARMENIAN_HYPHEN_STR;\n\t  case INSERT_MAQAF_AT_END:\n\t\treturn GlobalMembers.MAQAF_STR;\n\t  case INSERT_UCAS_HYPHEN_AT_END:\n\t\treturn GlobalMembers.UCAS_HYPHEN_STR;\n\t  case INSERT_ZWJ_AND_HYPHEN_AT_END:\n\t\treturn GlobalMembers.ZWJ_AND_HYPHEN_STR;\n\t  case INSERT_ZWJ_AT_START:\n\t\treturn GlobalMembers.ZWJ_STR;\n\t  default:\n\t\treturn null;\n\t}\n  }\n  public static uint editForThisLine(HyphenationType type)\n  {\n\tswitch (type)\n\t{\n\t  case HyphenationType.DONT_BREAK:\n\t\treturn NO_EDIT;\n\t  case HyphenationType.BREAK_AND_INSERT_HYPHEN:\n\t\treturn INSERT_HYPHEN_AT_END;\n\t  case HyphenationType.BREAK_AND_INSERT_ARMENIAN_HYPHEN:\n\t\treturn INSERT_ARMENIAN_HYPHEN_AT_END;\n\t  case HyphenationType.BREAK_AND_INSERT_MAQAF:\n\t\treturn INSERT_MAQAF_AT_END;\n\t  case HyphenationType.BREAK_AND_INSERT_UCAS_HYPHEN:\n\t\treturn INSERT_UCAS_HYPHEN_AT_END;\n\t  case HyphenationType.BREAK_AND_REPLACE_WITH_HYPHEN:\n\t\treturn REPLACE_WITH_HYPHEN_AT_END;\n\t  case HyphenationType.BREAK_AND_INSERT_HYPHEN_AND_ZWJ:\n\t\treturn INSERT_ZWJ_AND_HYPHEN_AT_END;\n\t  default:\n\t\treturn BREAK_AT_END;\n\t}\n  }\n  public static uint editForNextLine(HyphenationType type)\n  {\n\tswitch (type)\n\t{\n\t  case HyphenationType.DONT_BREAK:\n\t\treturn NO_EDIT;\n\t  case HyphenationType.BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE:\n\t\treturn INSERT_HYPHEN_AT_START;\n\t  case HyphenationType.BREAK_AND_INSERT_HYPHEN_AND_ZWJ:\n\t\treturn INSERT_ZWJ_AT_START;\n\t  default:\n\t\treturn BREAK_AT_START;\n\t}\n  }\n\n  public HyphenEdit()\n  {\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.hyphen = NO_EDIT;\n\t  this.hyphen.CopyFrom(NO_EDIT);\n  }\n  public HyphenEdit(uint hyphenInt)\n  {\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.hyphen = hyphenInt;\n\t  this.hyphen.CopyFrom(hyphenInt);\n  } // NOLINT(implicit)\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint getHyphen() const\n  public uint getHyphen()\n  {\n\t  return hyphen;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool operator ==(const HyphenEdit& other) const\n  public static bool operator == (HyphenEdit ImpliedObject, HyphenEdit other)\n  {\n\treturn ImpliedObject.hyphen == other.hyphen;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint getEnd() const\n  public uint getEnd()\n  {\n\t  return hyphen & MASK_END_OF_LINE;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint getStart() const\n  public uint getStart()\n  {\n\t  return hyphen & MASK_START_OF_LINE;\n  }\n\n  private uint hyphen = new uint();\n}\n\n// hyb file header; implementation details are in the .cpp file\n//C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n//struct Header;\n\npublic class Hyphenator\n{\n  // Compute the hyphenation of a word, storing the hyphenation in result\n  // vector. Each entry in the vector is a \"hyphenation type\" for a potential\n  // hyphenation that can be applied at the corresponding code unit offset in\n  // the word.\n  //\n  // Example: word is \"hyphen\", result is the following, corresponding to\n  // \"hy-phen\": [DONT_BREAK, DONT_BREAK, BREAK_AND_INSERT_HYPHEN, DONT_BREAK,\n  // DONT_BREAK, DONT_BREAK]\n//C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n//  void hyphenate(ClassicVector<HyphenationType> result, UInt16 word, int len, icu::Locale locale);\n\n  // Returns true if the codepoint is like U+2010 HYPHEN in line breaking and\n  // usage: a character immediately after which line breaks are allowed, but\n  // words containing it should not be automatically hyphenated.\n\n  // This function determines whether a character is like U+2010 HYPHEN in\n  // line breaking and usage: a character immediately after which line breaks\n  // are allowed, but words containing it should not be automatically\n  // hyphenated using patterns. This is a curated set, created by manually\n  // inspecting all the characters that have the Unicode line breaking\n  // property of BA or HY and seeing which ones are hyphens.\n  public static bool isLineBreakingHyphen(uint c)\n  {\n\treturn (c == 0x002D || c == 0x058A || c == 0x05BE || c == 0x1400 || c == 0x2010 || c == 0x2013 || c == 0x2027 || c == 0x2E17 || c == 0x2E40); // DOUBLE HYPHEN\n  }\n\n  // pattern data is in binary format, as described in doc/hyb_file_format.md.\n  // Note: the caller is responsible for ensuring that the lifetime of the\n  // pattern data is at least as long as the Hyphenator object.\n\n  // Note: nullptr is valid input, in which case the hyphenator only processes\n  // soft hyphens.\n  public static Hyphenator loadBinary(byte patternData, int minPrefix, int minSuffix)\n  {\n\tHyphenator result = new Hyphenator();\n\tresult.patternData = patternData;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: result->minPrefix = minPrefix;\n\tresult.minPrefix.CopyFrom(minPrefix);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: result->minSuffix = minSuffix;\n\tresult.minSuffix.CopyFrom(minSuffix);\n\treturn result;\n  }\n\n  // apply various hyphenation rules including hard and soft hyphens, ignoring\n  // patterns\n\n  // Use various recommendations of UAX #14 Unicode Line Breaking Algorithm for\n  // hyphenating words that didn't match patterns, especially words that contain\n  // hyphens or soft hyphens (See sections 5.3, Use of Hyphen, and 5.4, Use of\n  // Soft Hyphen).\n  private void hyphenateWithNoPatterns(HyphenationType[] result, UInt16[] word, int len, icu.Locale locale)\n  {\n\tresult[0] = HyphenationType.DONT_BREAK;\n\tfor (int i = 1; i < len; i++)\n\t{\n\t  UInt16 prevChar = word[i - 1];\n\t  if (i > 1 && isLineBreakingHyphen(new UInt16(prevChar)))\n\t  {\n\t\t// Break after hyphens, but only if they don't start the word.\n\n\t\tif ((prevChar == GlobalMembers.CHAR_HYPHEN_MINUS || prevChar == GlobalMembers.CHAR_HYPHEN) && string.Compare(locale.getLanguage(), \"pl\") == 0 && minikin.GlobalMembers.getScript(word[i]) == USCRIPT_LATIN)\n\t\t{\n\t\t  // In Polish, hyphens get repeated at the next line. To be safe,\n\t\t  // we will do this only if the next character is Latin.\n\t\t  result[i] = HyphenationType.BREAK_AND_INSERT_HYPHEN_AT_NEXT_LINE;\n\t\t}\n\t\telse\n\t\t{\n\t\t  result[i] = HyphenationType.BREAK_AND_DONT_INSERT_HYPHEN;\n\t\t}\n\t  }\n\t  else if (i > 1 && prevChar == GlobalMembers.CHAR_SOFT_HYPHEN)\n\t  {\n\t\t// Break after soft hyphens, but only if they don't start the word (a soft\n\t\t// hyphen starting the word doesn't give any useful break opportunities).\n\t\t// The type of the break is based on the script of the character we break\n\t\t// on.\n\t\tif (minikin.GlobalMembers.getScript(word[i]) == USCRIPT_ARABIC)\n\t\t{\n\t\t  // For Arabic, we need to look and see if the characters around the soft\n\t\t  // hyphen actually join. If they don't, we'll just insert a normal\n\t\t  // hyphen.\n\t\t  result[i] = minikin.GlobalMembers.getHyphTypeForArabic(new UInt16(word), len, i);\n\t\t}\n\t\telse\n\t\t{\n\t\t  result[i] = minikin.GlobalMembers.hyphenationTypeBasedOnScript(word[i]);\n\t\t}\n\t  }\n\t  else if (prevChar == GlobalMembers.CHAR_MIDDLE_DOT && minPrefix < i && i <= len - minSuffix && ((word[i - 2] == 'l' && word[i] == 'l') || (word[i - 2] == 'L' && word[i] == 'L')) && string.Compare(locale.getLanguage(), \"ca\") == 0)\n\t  {\n\t\t// In Catalan, \"l·l\" should break as \"l-\" on the first line\n\t\t// and \"l\" on the next line.\n\t\tresult[i] = HyphenationType.BREAK_AND_REPLACE_WITH_HYPHEN;\n\t  }\n\t  else\n\t  {\n\t\tresult[i] = HyphenationType.DONT_BREAK;\n\t  }\n\t}\n  }\n\n  // Try looking up word in alphabet table, return DONT_BREAK if any code units\n  // fail to map. Otherwise, returns BREAK_AND_INSERT_HYPHEN,\n  // BREAK_AND_INSERT_ARMENIAN_HYPHEN, or BREAK_AND_DONT_INSERT_HYPHEN based on\n  // the the script of the characters seen. Note that this method writes len+2\n  // entries into alpha_codes (including start and stop)\n  private HyphenationType alphabetLookup(UInt16[] alpha_codes, UInt16[] word, int len)\n  {\n\tHeader header = getHeader();\n\tHyphenationType result = HyphenationType.BREAK_AND_INSERT_HYPHEN;\n\t// TODO: check header magic\n\tuint alphabetVersion = header.alphabetVersion();\n\tif (alphabetVersion == 0)\n\t{\n\t  AlphabetTable0 alphabet = header.alphabetTable0();\n\t  uint min_codepoint = new uint(alphabet.min_codepoint);\n\t  uint max_codepoint = new uint(alphabet.max_codepoint);\n\t  alpha_codes[0] = 0; // word start\n\t  for (int i = 0; i < len; i++)\n\t  {\n\t\tUInt16 c = word[i];\n\t\tif (c < min_codepoint || c >= max_codepoint)\n\t\t{\n\t\t  return HyphenationType.DONT_BREAK;\n\t\t}\n\t\tbyte code = alphabet.data[c - min_codepoint];\n\t\tif (code == 0)\n\t\t{\n\t\t  return HyphenationType.DONT_BREAK;\n\t\t}\n\t\tif (result == HyphenationType.BREAK_AND_INSERT_HYPHEN)\n\t\t{\n\t\t  result = minikin.GlobalMembers.hyphenationTypeBasedOnScript(new UInt16(c));\n\t\t}\n\t\talpha_codes[i + 1] = code;\n\t  }\n\t  alpha_codes[len + 1] = 0; // word termination\n\t  return result;\n\t}\n\telse if (alphabetVersion == 1)\n\t{\n\t  AlphabetTable1 alphabet = header.alphabetTable1();\n\t  int n_entries = alphabet.n_entries;\n\t  uint[] begin = new uint(alphabet.data);\n\t  uint end = begin + n_entries;\n\t  alpha_codes[0] = 0;\n\t  for (int i = 0; i < len; i++)\n\t  {\n\t\tUInt16 c = word[i];\n\t\tvar p = std::lower_bound<uint*, uint>(begin, end, c << 11);\n\t\tif (p == end)\n\t\t{\n\t\t  return HyphenationType.DONT_BREAK;\n\t\t}\n\t\tuint entry = p;\n\t\tif (AlphabetTable1.codepoint(new uint(entry)) != c)\n\t\t{\n\t\t  return HyphenationType.DONT_BREAK;\n\t\t}\n\t\tif (result == HyphenationType.BREAK_AND_INSERT_HYPHEN)\n\t\t{\n\t\t  result = minikin.GlobalMembers.hyphenationTypeBasedOnScript(new UInt16(c));\n\t\t}\n\t\talpha_codes[i + 1] = AlphabetTable1.value(new uint(entry));\n\t  }\n\t  alpha_codes[len + 1] = 0;\n\t  return result;\n\t}\n\treturn HyphenationType.DONT_BREAK;\n  }\n\n  // calculate hyphenation from patterns, assuming alphabet lookup has already\n  // been done\n\n  /**\n   * Internal implementation, after conversion to codes. All case folding and\n   *normalization has been done by now, and all characters have been found in the\n   *alphabet. Note: len here is the padded length including 0 codes at start and\n   *end.\n   **/\n  private void hyphenateFromCodes(HyphenationType[] result, UInt16[] codes, int len, HyphenationType hyphenValue)\n  {\n  //C++ TO C# CONVERTER TODO TASK: There is no equivalent in C# to 'static_assert':\n  //  static_assert(sizeof(HyphenationType) == sizeof(byte), \"HyphnationType must be byte.\");\n\t// Reuse the result array as a buffer for calculating intermediate hyphenation\n\t// numbers.\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\tbyte[] buffer = reinterpret_cast<byte>(result);\n\n\tHeader header = getHeader();\n\tTrie trie = header.trieTable();\n\tPattern pattern = header.patternTable();\n\tuint char_mask = new uint(trie.char_mask);\n\tuint link_shift = new uint(trie.link_shift);\n\tuint link_mask = new uint(trie.link_mask);\n\tuint pattern_shift = new uint(trie.pattern_shift);\n\tint maxOffset = len - minSuffix - 1;\n\tfor (int i = 0; i < len - 1; i++)\n\t{\n\t  uint node = 0; // index into Trie table\n\t  for (int j = i; j < len; j++)\n\t  {\n\t\tUInt16 c = codes[j];\n\t\tuint entry = trie.data[node + c];\n\t\tif ((entry & char_mask) == c)\n\t\t{\n\t\t  node = (entry & link_mask) >> link_shift;\n\t\t}\n\t\telse\n\t\t{\n\t\t  break;\n\t\t}\n\t\tuint pat_ix = trie.data[node] >> pattern_shift;\n\t\t// pat_ix contains a 3-tuple of length, shift (number of trailing zeros),\n\t\t// and an offset into the buf pool. This is the pattern for the substring\n\t\t// (i..j) we just matched, which we combine (via point-wise max) into the\n\t\t// buffer vector.\n\t\tif (pat_ix != 0)\n\t\t{\n\t\t  uint pat_entry = pattern.data[pat_ix];\n\t\t  int pat_len = Pattern.len(new uint(pat_entry));\n\t\t  int pat_shift = Pattern.shift(new uint(pat_entry));\n\t\t  byte[] pat_buf = pattern.buf(new uint(pat_entry));\n\t\t  int offset = j + 1 - (pat_len + pat_shift);\n\t\t  // offset is the index within buffer that lines up with the start of\n\t\t  // pat_buf\n\t\t  int start = Math.Max((int)minPrefix - offset, 0);\n\t\t  int end = Math.Min(pat_len, (int)maxOffset - offset);\n\t\t  for (int k = start; k < end; k++)\n\t\t  {\n\t\t\tbuffer[offset + k] = Math.Max(buffer[offset + k], pat_buf[k]);\n\t\t  }\n\t\t}\n\t  }\n\t}\n\t// Since the above calculation does not modify values outside\n\t// [minPrefix, len - minSuffix], they are left as 0 = DONT_BREAK.\n\tfor (int i = minPrefix; i < maxOffset; i++)\n\t{\n\t  // Hyphenation opportunities happen when the hyphenation numbers are odd.\n\t  result[i] = ((buffer[i] & 1u) != null) ? hyphenValue : HyphenationType.DONT_BREAK;\n\t}\n  }\n\n  // See also LONGEST_HYPHENATED_WORD in LineBreaker.cpp. Here the constant is\n  // used so that temporary buffers can be stack-allocated without waste, which\n  // is a slightly different use case. It measures UTF-16 code units.\n  private const int MAX_HYPHENATED_SIZE = 64;\n\n  private readonly byte patternData;\n  private int minPrefix = new int();\n  private int minSuffix = new int();\n\n  // accessors for binary data\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const Header* getHeader() const\n  private Header getHeader()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const Header>(patternData);\n  }\n}\n\n} // namespace minikin\n\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n\n\nnamespace minikin\n{\n\n// The following are structs that correspond to tables inside the hyb file\n// format\n\npublic class AlphabetTable0\n{\n  public uint version = new uint();\n  public uint min_codepoint = new uint();\n  public uint max_codepoint = new uint();\n  public byte[] data = Arrays.InitializeWithDefaultInstances<byte>(1); // actually flexible array, size is known at runtime\n}\n\npublic class AlphabetTable1\n{\n  public uint version = new uint();\n  public uint n_entries = new uint();\n  public uint[] data = Arrays.InitializeWithDefaultInstances<uint>(1); // actually flexible array, size is known at runtime\n\n  public static uint codepoint(uint entry)\n  {\n\t  return entry >> 11;\n  }\n  public static uint value(uint entry)\n  {\n\t  return entry & 0x7ff;\n  }\n}\n\npublic class Trie\n{\n  public uint version = new uint();\n  public uint char_mask = new uint();\n  public uint link_shift = new uint();\n  public uint link_mask = new uint();\n  public uint pattern_shift = new uint();\n  public uint n_entries = new uint();\n  public uint[] data = Arrays.InitializeWithDefaultInstances<uint>(1); // actually flexible array, size is known at runtime\n}\n\npublic class Pattern\n{\n  public uint version = new uint();\n  public uint n_entries = new uint();\n  public uint pattern_offset = new uint();\n  public uint pattern_size = new uint();\n  public uint[] data = Arrays.InitializeWithDefaultInstances<uint>(1); // actually flexible array, size is known at runtime\n\n  // accessors\n  public static uint len(uint entry)\n  {\n\t  return entry >> 26;\n  }\n  public static uint shift(uint entry)\n  {\n\t  return (entry >> 20) & 0x3f;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const byte* buf(uint entry) const\n  public byte buf(uint entry)\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const byte>(this) + pattern_offset + (entry & 0xfffff);\n  }\n}\n\npublic class Header\n{\n  public uint magic = new uint();\n  public uint version = new uint();\n  public uint alphabet_offset = new uint();\n  public uint trie_offset = new uint();\n  public uint pattern_offset = new uint();\n  public uint file_size = new uint();\n\n  // accessors\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const byte* bytes() const\n  public byte bytes()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const byte>(this);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint alphabetVersion() const\n  public uint alphabetVersion()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn *reinterpret_cast<const uint>(bytes() + alphabet_offset);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const AlphabetTable0* alphabetTable0() const\n  public AlphabetTable0 alphabetTable0()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const AlphabetTable0>(bytes() + alphabet_offset);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const AlphabetTable1* alphabetTable1() const\n  public AlphabetTable1 alphabetTable1()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const AlphabetTable1>(bytes() + alphabet_offset);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const Trie* trieTable() const\n  public Trie trieTable()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const Trie>(bytes() + trie_offset);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const Pattern* patternTable() const\n  public Pattern patternTable()\n  {\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const Pattern>(bytes() + pattern_offset);\n  }\n}\n\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/Layout.cs",
    "content": "﻿/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace minikin\n{\n\npublic class LayoutContext\n{\n  public MinikinPaint paint = new MinikinPaint();\n  public FontStyle style = new FontStyle();\n  public List<HarfBuzzSharp.Font> hbFonts = new List<HarfBuzzSharp.Font>(); // parallel to mFaces\n\n  public void clearHbFonts()\n  {\n\tfor (int i = 0; i < hbFonts.Count; i++)\n\t{\n\t  hb_font_set_funcs(hbFonts[i], null, null, null);\n\t  hb_font_destroy(hbFonts[i]);\n\t}\n\thbFonts.Clear();\n  }\n}\n\n// Layout cache datatypes\n\npublic class LayoutCacheKey\n{\n  public LayoutCacheKey(FontCollection collection, MinikinPaint paint, FontStyle style, UInt16 chars, int start, int count, int nchars, bool dir)\n  {\n\t  this.mChars = chars;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mNchars = nchars;\n\t  this.mNchars.CopyFrom(nchars);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mStart = start;\n\t  this.mStart.CopyFrom(start);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mCount = count;\n\t  this.mCount.CopyFrom(count);\n\t  this.mId = collection.getId();\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mStyle = style;\n\t  this.mStyle.CopyFrom(style);\n\t  this.mSize = paint.size;\n\t  this.mScaleX = paint.scaleX;\n\t  this.mSkewX = paint.skewX;\n\t  this.mLetterSpacing = paint.letterSpacing;\n\t  this.mPaintFlags = paint.paintFlags;\n\t  this.mHyphenEdit = paint.hyphenEdit;\n\t  this.mIsRtl = dir;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mHash = computeHash();\n\t  this.mHash.CopyFrom(computeHash());\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool operator ==(const LayoutCacheKey& other) const\n  public static bool operator == (LayoutCacheKey ImpliedObject, LayoutCacheKey other)\n  {\n//C++ TO C# CONVERTER TODO TASK: The memory management function 'memcmp' has no equivalent in C#:\n\treturn ImpliedObject.mId == other.mId && ImpliedObject.mStart == other.mStart && ImpliedObject.mCount == other.mCount && ImpliedObject.mStyle == other.mStyle && ImpliedObject.mSize == other.mSize && ImpliedObject.mScaleX == other.mScaleX && ImpliedObject.mSkewX == other.mSkewX && ImpliedObject.mLetterSpacing == other.mLetterSpacing && ImpliedObject.mPaintFlags == other.mPaintFlags && ImpliedObject.mHyphenEdit == other.mHyphenEdit && ImpliedObject.mIsRtl == other.mIsRtl && ImpliedObject.mNchars == other.mNchars && !memcmp(ImpliedObject.mChars, other.mChars, ImpliedObject.mNchars * sizeof(UInt16));\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: android::hash_t hash() const\n  public android.hash_t hash()\n  {\n\t  return mHash;\n  }\n\n  public void copyText()\n  {\n\tUInt16[] charsCopy = Arrays.InitializeWithDefaultInstances<UInt16>(mNchars);\n//C++ TO C# CONVERTER TODO TASK: The memory management function 'memcpy' has no equivalent in C#:\n\tmemcpy(charsCopy, mChars, mNchars * sizeof(UInt16));\n\tmChars = charsCopy;\n  }\n  public void freeText()\n  {\n\tmChars = null;\n\tmChars = null;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void doLayout(Layout* layout, LayoutContext* ctx, const FontCollection*& collection) const\n  public void doLayout(Layout layout, LayoutContext ctx, FontCollection collection)\n  {\n\tlayout.mAdvances.resize(mCount, 0);\n\tctx.clearHbFonts();\n\tlayout.doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx, collection);\n  }\n\n  private readonly UInt16 mChars;\n  private int mNchars = new int();\n  private int mStart = new int();\n  private int mCount = new int();\n  private uint mId = new uint(); // for the font collection\n  private FontStyle mStyle = new FontStyle();\n  private float mSize;\n  private float mScaleX;\n  private float mSkewX;\n  private float mLetterSpacing;\n  private int mPaintFlags = new int();\n  private HyphenEdit mHyphenEdit = new HyphenEdit();\n  private bool mIsRtl;\n  // Note: any fields added to MinikinPaint must also be reflected here.\n  // TODO: language matching (possibly integrate into style)\n  private android.hash_t mHash = new android.hash_t();\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: android::hash_t computeHash() const\n  private android.hash_t computeHash()\n  {\n\tuint hash = android.JenkinsHashMix(0, mId);\n\thash = android.JenkinsHashMix(hash, mStart);\n\thash = android.JenkinsHashMix(hash, mCount);\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mStyle));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mSize));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mScaleX));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mSkewX));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mLetterSpacing));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mPaintFlags));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mHyphenEdit.getHyphen()));\n\thash = android.JenkinsHashMix(hash, minikin.GlobalMembers.hash_type(mIsRtl));\n\thash = android.JenkinsHashMixShorts(hash, mChars, mNchars);\n\treturn android.JenkinsHashWhiten(hash);\n  }\n}\n\n//C++ TO C# CONVERTER TODO TASK: C# has no concept of 'private' inheritance:\n//ORIGINAL LINE: class LayoutCache : private android::OnEntryRemoved<LayoutCacheKey, Layout*>\npublic class LayoutCache : android.OnEntryRemoved<LayoutCacheKey, Layout*>\n{\n  public LayoutCache()\n  {\n\t  this.mCache = kMaxEntries;\n\tmCache.setOnEntryRemovedListener(this.functorMethod);\n  }\n\n  public void clear()\n  {\n\t  mCache.clear();\n  }\n\n  public Layout get(LayoutCacheKey key, LayoutContext ctx, FontCollection collection)\n  {\n\tLayout layout = mCache.get(key);\n\tif (layout == null)\n\t{\n\t  key.copyText();\n\t  layout = new Layout();\n\t  key.doLayout(layout, ctx, collection);\n\t  mCache.put(key, layout);\n\t}\n\treturn layout;\n  }\n\n  // callback for OnEntryRemoved\n  private static void functorMethod(LayoutCacheKey key, ref Layout value)\n  {\n\tkey.freeText();\n\tvalue = null;\n  }\n\n  private android.LruCache<LayoutCacheKey, Layout> mCache = new android.LruCache<LayoutCacheKey, Layout>();\n\n  // static const int kMaxEntries = LruCache<LayoutCacheKey,\n  // Layout*>::kUnlimitedCapacity;\n\n  // TODO: eviction based on memory footprint; for now, we just use a constant\n  // number of strings\n  private const int kMaxEntries = 5000;\n}\n\npublic class LayoutEngine\n{\n  public LayoutEngine()\n  {\n\tunicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());\n\t/* Disable the function used for compatibility decomposition */\n\thb_unicode_funcs_set_decompose_compatibility_func(unicodeFunctions, minikin.GlobalMembers.disabledDecomposeCompatibility, null, null);\n\thbBuffer = hb_buffer_create();\n\thb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions);\n  }\n\n  public hb_buffer_t hbBuffer;\n  public hb_unicode_funcs_t unicodeFunctions;\n  public LayoutCache layoutCache = new LayoutCache();\n\n//C++ TO C# CONVERTER NOTE: This was formerly a static local variable declaration (not allowed in C#):\n  private static LayoutEngine getInstance_instance = new LayoutEngine();\n  public static LayoutEngine getInstance()\n  {\n//C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method:\n//\tstatic LayoutEngine* instance = new LayoutEngine();\n\treturn getInstance_instance;\n  }\n}\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void Layout::dump() const\n\n\npublic class BidiText : System.IDisposable\n{\n  public class Iter\n  {\n\tpublic class RunInfo\n\t{\n\t  public int mRunStart = new int();\n\t  public int mRunLength = new int();\n\t  public bool mIsRtl;\n\t}\n\n\tpublic Iter(UBiDi bidi, int start, int end, int runIndex, int runCount, bool isRtl)\n\t{\n\t\tthis.mBidi = bidi;\n\t\tthis.mIsEnd = runIndex == runCount;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mNextRunIndex = runIndex;\n\t\tthis.mNextRunIndex.CopyFrom(runIndex);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mRunCount = runCount;\n\t\tthis.mRunCount.CopyFrom(runCount);\n\t\tthis.mStart = start;\n\t\tthis.mEnd = end;\n\t\tthis.mRunInfo = new minikin.BidiText.Iter.RunInfo();\n\t  if (mRunCount == 1)\n\t  {\n\t\tmRunInfo.mRunStart = start;\n\t\tmRunInfo.mRunLength = end - start;\n\t\tmRunInfo.mIsRtl = isRtl;\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: mNextRunIndex = mRunCount;\n\t\tmNextRunIndex.CopyFrom(mRunCount);\n\t\treturn;\n\t  }\n\t  updateRunInfo();\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool operator !=(const Iter& other) const\n\tpublic static bool operator != (Iter ImpliedObject, Iter other)\n\t{\n\t  return ImpliedObject.mIsEnd != other.mIsEnd || ImpliedObject.mNextRunIndex != other.mNextRunIndex || ImpliedObject.mBidi != other.mBidi;\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const RunInfo& operator *() const\n\tpublic RunInfo Indirection()\n\t{\n\t\treturn mRunInfo;\n\t}\n\n\tpublic static Iter operator ++(Iter ImpliedObject)\n\t{\n\t  ImpliedObject.updateRunInfo();\n\t  return *ImpliedObject;\n\t}\n\n\tprivate readonly UBiDi mBidi;\n\tprivate bool mIsEnd;\n\tprivate int mNextRunIndex = new int();\n\tprivate readonly int mRunCount = new int();\n\tprivate readonly int mStart = new int();\n\tprivate readonly int mEnd = new int();\n\tprivate RunInfo mRunInfo = new RunInfo();\n\n\tprivate void updateRunInfo()\n\t{\n\t  if (mNextRunIndex == mRunCount)\n\t  {\n\t\t// All runs have been iterated.\n\t\tmIsEnd = true;\n\t\treturn;\n\t  }\n\t  int startRun = -1;\n\t  int lengthRun = -1;\n\t  UBiDiDirection runDir = ubidi_getVisualRun(mBidi, mNextRunIndex, startRun, lengthRun);\n\t  mNextRunIndex++;\n\t  if (startRun == -1 || lengthRun == -1)\n\t  {\n\t\tALOGE(\"invalid visual run\");\n\t\t// skip the invalid run.\n\t\tupdateRunInfo();\n\t\treturn;\n\t  }\n\t  int runEnd = Math.Min(startRun + lengthRun, mEnd);\n\t  mRunInfo.mRunStart = Math.Max(startRun, mStart);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: mRunInfo.mRunLength = runEnd - mRunInfo.mRunStart;\n\t  mRunInfo.mRunLength.CopyFrom(runEnd - mRunInfo.mRunStart);\n\t  if (mRunInfo.mRunLength <= 0)\n\t  {\n\t\t// skip the empty run.\n\t\tupdateRunInfo();\n\t\treturn;\n\t  }\n\t  mRunInfo.mIsRtl = (runDir == UBIDI_RTL);\n\t}\n  }\n\n  public BidiText(UInt16 buf, int start, int count, int bufSize, int bidiFlags)\n  {\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mStart = start;\n\t  this.mStart.CopyFrom(start);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mEnd = start + count;\n\t  this.mEnd.CopyFrom(start + count);\n//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n//ORIGINAL LINE: this.mBufSize = bufSize;\n\t  this.mBufSize.CopyFrom(bufSize);\n\t  this.mBidi = null;\n\t  this.mRunCount = 1;\n\t  this.mIsRtl = (bidiFlags & GlobalMembers.kDirection_Mask) != 0;\n\tif (bidiFlags == kBidi_Force_LTR || bidiFlags == kBidi_Force_RTL)\n\t{\n\t  // force single run.\n\t  return;\n\t}\n\tmBidi = ubidi_open();\n\tif (mBidi == null)\n\t{\n\t  ALOGE(\"error creating bidi object\");\n\t  return;\n\t}\n\tUErrorCode status = U_ZERO_ERROR;\n\t// Set callbacks to override bidi classes of new emoji\n\tubidi_setClassCallback(mBidi, emojiBidiOverride, null, null, null, status);\n\tif (!U_SUCCESS(status))\n\t{\n\t  ALOGE(\"error setting bidi callback function, status = %d\", status);\n\t  return;\n\t}\n\n\tUBiDiLevel bidiReq = bidiFlags;\n\tif (bidiFlags == kBidi_Default_LTR)\n\t{\n\t  bidiReq = UBIDI_DEFAULT_LTR;\n\t}\n\telse if (bidiFlags == kBidi_Default_RTL)\n\t{\n\t  bidiReq = UBIDI_DEFAULT_RTL;\n\t}\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\tubidi_setPara(mBidi, reinterpret_cast<const UChar>(buf), mBufSize, bidiReq, null, status);\n\tif (!U_SUCCESS(status))\n\t{\n\t  ALOGE(\"error calling ubidi_setPara, status = %d\", status);\n\t  return;\n\t}\n\tint paraDir = ubidi_getParaLevel(mBidi) & GlobalMembers.kDirection_Mask;\n\tuint rc = ubidi_countRuns(mBidi, status);\n\tif (!U_SUCCESS(status) || rc < 0)\n\t{\n\t  ALOGW(\"error counting bidi runs, status = %d\", status);\n\t}\n\tif (!U_SUCCESS(status) || rc <= 1)\n\t{\n\t  mIsRtl = (paraDir == kBidi_RTL);\n\t  return;\n\t}\n\tmRunCount = rc;\n  }\n\n  public void Dispose()\n  {\n\tif (mBidi != null)\n\t{\n\t  ubidi_close(mBidi);\n\t}\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: Iter begin() const\n  public Iter begin()\n  {\n\t  return new Iter(mBidi, mStart, mEnd, 0, mRunCount, mIsRtl);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: Iter end() const\n  public Iter end()\n  {\n\treturn new Iter(mBidi, mStart, mEnd, mRunCount, mRunCount, mIsRtl);\n  }\n\n  private readonly int mStart = new int();\n  private readonly int mEnd = new int();\n  private readonly int mBufSize = new int();\n  private UBiDi mBidi;\n  private int mRunCount = new int();\n  private bool mIsRtl;\n\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  BidiText(const BidiText&) = delete;\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  void operator =(const BidiText&) = delete;\n}\n\n\n\n\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int Layout::nGlyphs() const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const MinikinFont* Layout::getFont(int i) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: FontFakery Layout::getFakery(int i) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint Layout::getGlyphId(int i) const\n\n// libtxt extension\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint Layout::getGlyphCluster(int i) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float Layout::getX(int i) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float Layout::getY(int i) const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float Layout::getAdvance() const\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void Layout::getBounds(MinikinRect* bounds) const\n\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/Layout.h.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\nnamespace minikin\n{\n\npublic class LayoutGlyph\n{\n  // index into mFaces and mHbFonts vectors. We could imagine\n  // moving this into a run length representation, because it's\n  // more efficient for long strings, and we'll probably need\n  // something like that for paint attributes (color, underline,\n  // fake b/i, etc), as having those per-glyph is bloated.\n  public int font_ix;\n\n  public uint glyph_id;\n  public float x;\n  public float y;\n\n  // libtxt extension: record the cluster (character index) that corresponds\n  // to this glyph\n  public uint cluster = new uint();\n}\n\n// Internal state used during layout operation\n//C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n//struct LayoutContext;\n\n//C++ TO C# CONVERTER NOTE: Enums must be named in C#, so the following enum has been named AnonymousEnum:\npublic enum AnonymousEnum\n{\n  kBidi_LTR = 0,\n  kBidi_RTL = 1,\n  kBidi_Default_LTR = 2,\n  kBidi_Default_RTL = 3,\n  kBidi_Force_LTR = 4,\n  kBidi_Force_RTL = 5,\n\n  kBidi_Mask = 0x7\n}\n\n// Lifecycle and threading assumptions for Layout:\n// The object is assumed to be owned by a single thread; multiple threads\n// may not mutate it at the same time.\npublic class Layout\n{\n  public Layout()\n  {\n\t  this.mGlyphs = new List<LayoutGlyph>();\n\t  this.mAdvances = new List<float>();\n\t  this.mFaces = new List<FakedFont>();\n\t  this.mAdvance = 0F;\n\t  this.mBounds = new MinikinRect();\n\tmBounds.setEmpty();\n  }\n\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//  Layout(Layout&& layout) = default;\n\n  // Forbid copying and assignment.\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  Layout(const Layout&) = delete;\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  void operator =(const Layout&) = delete;\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void dump() const;\n\tpublic void dump()\n\t{\n\t  for (int i = 0; i < mGlyphs.size(); i++)\n\t  {\n\t\tLayoutGlyph glyph = mGlyphs[i];\n\t\tConsole.Write(glyph.glyph_id);\n\t\tConsole.Write(\": \");\n\t\tConsole.Write(glyph.x);\n\t\tConsole.Write(\", \");\n\t\tConsole.Write(glyph.y);\n\t\tConsole.Write(\"\\n\");\n\t  }\n\t}\n\n\tpublic void doLayout(UInt16 buf, int start, int count, int bufSize, bool isRtl, FontStyle style, MinikinPaint paint, FontCollection collection)\n\t{\n\t  std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n    \n\t  LayoutContext ctx = new LayoutContext();\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: ctx.style = style;\n\t  ctx.style.CopyFrom(style);\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: ctx.paint = paint;\n\t  ctx.paint.CopyFrom(paint);\n    \n\t  reset();\n\t  mAdvances.resize(count, 0);\n    \n\t  doLayoutRunCached(buf, start, count, bufSize, isRtl, ctx, start, collection, this, null);\n    \n\t  ctx.clearHbFonts();\n\t}\n\n\tpublic float measureText(UInt16 buf, int start, int count, int bufSize, bool isRtl, FontStyle style, MinikinPaint paint, FontCollection collection, ref float advances)\n\t{\n\t  std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n    \n\t  LayoutContext ctx = new LayoutContext();\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: ctx.style = style;\n\t  ctx.style.CopyFrom(style);\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: ctx.paint = paint;\n\t  ctx.paint.CopyFrom(paint);\n    \n\t  float advance = doLayoutRunCached(buf, start, count, bufSize, isRtl, ctx, 0, collection, null, advances);\n    \n\t  ctx.clearHbFonts();\n\t  return advance;\n\t}\n\n  // public accessors\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int nGlyphs() const;\n\tpublic int nGlyphs()\n\t{\n\t  return mGlyphs.size();\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const MinikinFont* getFont(int i) const;\n\tpublic MinikinFont getFont(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return mFaces[glyph.font_ix].font;\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: FontFakery getFakery(int i) const;\n\tpublic FontFakery getFakery(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return mFaces[glyph.font_ix].fakery;\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint getGlyphId(int i) const;\n\tpublic uint getGlyphId(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return glyph.glyph_id;\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint getGlyphCluster(int i) const;\n\tpublic uint getGlyphCluster(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return glyph.cluster;\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getX(int i) const;\n\tpublic float getX(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return glyph.x;\n\t}\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getY(int i) const;\n\tpublic float getY(int i)\n\t{\n\t  LayoutGlyph glyph = mGlyphs[i];\n\t  return glyph.y;\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getAdvance() const;\n\tpublic float getAdvance()\n\t{\n\t  return mAdvance;\n\t}\n\n  // Get advances, copying into caller-provided buffer. The size of this\n  // buffer must match the length of the string (count arg to doLayout).\n\tpublic void getAdvances(ref float advances)\n\t{\n\t//C++ TO C# CONVERTER TODO TASK: The memory management function 'memcpy' has no equivalent in C#:\n\t  memcpy(advances, mAdvances[0], mAdvances.size() * sizeof(float));\n\t}\n\n  // The i parameter is an offset within the buf relative to start, it is <\n  // count, where start and count are the parameters to doLayout\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getCharAdvance(int i) const\n  public float getCharAdvance(int i)\n  {\n\t  return mAdvances[i];\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: void getBounds(MinikinRect* rect) const;\n\tpublic void getBounds(MinikinRect bounds)\n\t{\n\t  bounds.set(mBounds);\n\t}\n\n  // Purge all caches, useful in low memory conditions\n\tpublic void purgeCaches()\n\t{\n\t  std::lock_guard<std::recursive_mutex> _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n\t  LayoutCache layoutCache = LayoutEngine.getInstance().layoutCache.functorMethod;\n\t  layoutCache.clear();\n\t  purgeHbFontCacheLocked();\n\t}\n\n//C++ TO C# CONVERTER TODO TASK: C# has no concept of a 'friend' class:\n//  friend class LayoutCacheKey;\n\n  // Find a face in the mFaces vector, or create a new entry\n\tpublic int findFace(FakedFont face, LayoutContext ctx)\n\t{\n\t  uint ix;\n\t  for (ix = 0; ix < mFaces.size(); ix++)\n\t  {\n\t\tif (mFaces[ix].font == face.font)\n\t\t{\n\t\t  return ix;\n\t\t}\n\t  }\n\t  mFaces.push_back(face);\n\t  // Note: ctx == NULL means we're copying from the cache, no need to create\n\t  // corresponding hb_font object.\n\t  if (ctx != null)\n\t  {\n\t\tHarfBuzzSharp.Font font = getHbFontLocked(face.font);\n\t\t// Temporarily removed to fix advance integer rounding.\n\t\t// This is likely due to very old versions of harfbuzz and ICU.\n\t\t// hb_font_set_funcs(font, getHbFontFuncs(isColorBitmapFont(font)),\n\t\t// &ctx->paint, 0);\n\t\tctx.hbFonts.Add(font);\n\t  }\n\t  return ix;\n\t}\n\n  // Clears layout, ready to be used again\n\tpublic void reset()\n\t{\n\t  mGlyphs.clear();\n\t  mFaces.clear();\n\t  mBounds.setEmpty();\n\t  mAdvances.clear();\n\t  mAdvance = 0;\n\t}\n\n  // Lay out a single bidi run\n  // When layout is not null, layout info will be stored in the object.\n  // When advances is not null, measurement results will be stored in the array.\n\tpublic float doLayoutRunCached(UInt16 buf, int start, int count, int bufSize, bool isRtl, LayoutContext ctx, int dstStart, FontCollection collection, Layout layout, ref float advances)\n\t{\n\t  uint originalHyphen = ctx.paint.hyphenEdit.getHyphen();\n\t  float advance = 0F;\n\t  if (!isRtl)\n\t  {\n\t\t// left to right\n\t\tint wordstart = start == bufSize != null ? start : getPrevWordBreakForCache(buf, start + 1, bufSize);\n\t\tint wordend = new int();\n\t\tfor (int iter = start; iter < start + count; iter = wordend)\n\t\t{\n\t\t  wordend = getNextWordBreakForCache(buf, iter, bufSize);\n\t\t  // Only apply hyphen to the first or last word in the string.\n\t\t  uint hyphen = new uint(originalHyphen);\n\t\t  if (iter != start)\n\t\t  { // Not the first word\n\t\t\thyphen &= ~HyphenEdit.MASK_START_OF_LINE;\n\t\t  }\n\t\t  if (wordend < start + count)\n\t\t  { // Not the last word\n\t\t\thyphen &= ~HyphenEdit.MASK_END_OF_LINE;\n\t\t  }\n\t\t  ctx.paint.hyphenEdit = hyphen;\n\t\t  int wordcount = Math.Min(start + count, wordend) - iter;\n\t\t  advance += doLayoutWord(buf + wordstart, iter - wordstart, wordcount, wordend - wordstart, isRtl, ctx, iter - dstStart, collection, layout, advances != 0 ? advances + (iter - start) : advances);\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: wordstart = wordend;\n\t\t  wordstart.CopyFrom(wordend);\n\t\t}\n\t  }\n\t  else\n\t  {\n\t\t// right to left\n\t\tint wordstart = new int();\n\t\tint end = start + count;\n\t\tint wordend = end == 0 ? 0 : getNextWordBreakForCache(buf, end - 1, bufSize);\n\t\tfor (int iter = end; iter > start; iter = wordstart)\n\t\t{\n\t\t  wordstart = getPrevWordBreakForCache(buf, iter, bufSize);\n\t\t  // Only apply hyphen to the first (rightmost) or last (leftmost) word in\n\t\t  // the string.\n\t\t  uint hyphen = new uint(originalHyphen);\n\t\t  if (wordstart > start)\n\t\t  { // Not the first word\n\t\t\thyphen &= ~HyphenEdit.MASK_START_OF_LINE;\n\t\t  }\n\t\t  if (iter != end)\n\t\t  { // Not the last word\n\t\t\thyphen &= ~HyphenEdit.MASK_END_OF_LINE;\n\t\t  }\n\t\t  ctx.paint.hyphenEdit = hyphen;\n\t\t  int bufStart = Math.Max(start, wordstart);\n\t\t  advance += doLayoutWord(buf + wordstart, bufStart - wordstart, iter - bufStart, wordend - wordstart, isRtl, ctx, bufStart - dstStart, collection, layout, advances != 0 ? advances + (bufStart - start) : advances);\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: wordend = wordstart;\n\t\t  wordend.CopyFrom(wordstart);\n\t\t}\n\t  }\n\t  return advance;\n\t}\n\n  // Lay out a single word\n\tpublic float doLayoutWord(UInt16[] buf, int start, int count, int bufSize, bool isRtl, LayoutContext ctx, int bufStart, FontCollection collection, Layout layout, float[] advances)\n\t{\n\t  LayoutCache cache = LayoutEngine.getInstance().layoutCache.functorMethod;\n\t  LayoutCacheKey key = new LayoutCacheKey(collection, ctx.paint, new FontStyle(ctx.style), new UInt16(buf), start, count, bufSize, isRtl);\n    \n\t  float wordSpacing = count == 1 && isWordSpace(buf[start]) ? ctx.paint.wordSpacing : 0F;\n    \n\t  float advance;\n\t  if (ctx.paint.skipCache())\n\t  {\n\t\tLayout layoutForWord = new Layout();\n\t\tkey.doLayout(layoutForWord, ctx, collection);\n\t\tif (layout != null)\n\t\t{\n\t\t  layout.appendLayout(layoutForWord, bufStart, wordSpacing);\n\t\t}\n\t\tif (advances != 0F)\n\t\t{\n\t\t  layoutForWord.getAdvances(advances);\n\t\t}\n\t\tadvance = layoutForWord.getAdvance();\n\t  }\n\t  else\n\t  {\n\t\tLayout layoutForWord = cache.get(key, ctx, collection);\n\t\tif (layout != null)\n\t\t{\n\t\t  layout.appendLayout(layoutForWord, bufStart, wordSpacing);\n\t\t}\n\t\tif (advances != 0F)\n\t\t{\n\t\t  layoutForWord.getAdvances(advances);\n\t\t}\n\t\tadvance = layoutForWord.getAdvance();\n\t  }\n    \n\t  if (wordSpacing != 0F)\n\t  {\n\t\tadvance += wordSpacing;\n\t\tif (advances != 0F)\n\t\t{\n\t\t  advances[0] += wordSpacing;\n\t\t}\n\t  }\n\t  return advance;\n\t}\n\n  // Lay out a single bidi run\n\tpublic void doLayoutRun(UInt16[] buf, int start, int count, int bufSize, bool isRtl, LayoutContext ctx, FontCollection collection)\n\t{\n\t  hb_buffer_t buffer = LayoutEngine.getInstance().hbBuffer;\n\t  vector<FontCollection.Run> items = new vector<FontCollection.Run>();\n\t  collection.itemize(buf + start, count, ctx.style, items);\n    \n\t  vector<hb_feature_t> features = new vector<hb_feature_t>();\n\t  // Disable default-on non-required ligature features if letter-spacing\n\t  // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property\n\t  // \"When the effective spacing between two characters is not zero (due to\n\t  // either justification or a non-zero value of letter-spacing), user agents\n\t  // should not apply optional ligatures.\"\n\t  if (Math.Abs(ctx.paint.letterSpacing) > 0.03)\n\t  {\n\t\thb_feature_t no_liga = new hb_feature_t(HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u);\n\t\thb_feature_t no_clig = new hb_feature_t(HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u);\n\t\tfeatures.push_back(no_liga);\n\t\tfeatures.push_back(no_clig);\n\t  }\n\t  addFeatures(ctx.paint.fontFeatureSettings, features);\n    \n\t  double size = ctx.paint.size;\n\t  double scaleX = ctx.paint.scaleX;\n    \n\t  float x = mAdvance;\n\t  float y = 0F;\n\t  for (int run_ix = isRtl ? items.size() - 1 : 0; isRtl ? run_ix >= 0 : run_ix < (int)items.size(); isRtl ?--run_ix :++run_ix)\n\t  {\n\t\tFontCollection.Run run = items[run_ix];\n\t\tif (run.fakedFont.font == null)\n\t\t{\n\t\t  ALOGE(\"no font for run starting u+%04x length %d\", buf[run.start], run.end - run.start);\n\t\t  continue;\n\t\t}\n\t\tint font_ix = findFace(run.fakedFont, ctx);\n\t\tctx.paint.font = mFaces[font_ix].font;\n\t\tctx.paint.fakery = mFaces[font_ix].fakery;\n\t\tHarfBuzzSharp.Font hbFont = ctx.hbFonts[font_ix];\n\t#if VERBOSE_DEBUG\n\t\tALOGD(\"Run %zu, font %d [%d:%d]\", run_ix, font_ix, run.start, run.end);\n\t#endif\n    \n\t\thb_font_set_ppem(hbFont, size * scaleX, size);\n\t\thb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));\n    \n\t\tbool is_color_bitmap_font = isColorBitmapFont(hbFont);\n    \n\t\t// TODO: if there are multiple scripts within a font in an RTL run,\n\t\t// we need to reorder those runs. This is unlikely with our current\n\t\t// font stack, but should be done for correctness.\n    \n\t\t// Note: scriptRunStart and scriptRunEnd, as well as run.start and run.end,\n\t\t// run between 0 and count.\n\t\tuint scriptRunEnd;\n\t\tfor (uint scriptRunStart = run.start; scriptRunStart < run.end; scriptRunStart = scriptRunEnd)\n\t\t{\n\t\t  scriptRunEnd = scriptRunStart;\n\t\t  hb_script_t script = getScriptRun(buf + start, run.end, ref scriptRunEnd);\n\t\t  // After the last line, scriptRunEnd is guaranteed to have increased,\n\t\t  // since the only time getScriptRun does not increase its iterator is when\n\t\t  // it has already reached the end of the buffer. But that can't happen,\n\t\t  // since if we have already reached the end of the buffer, we should have\n\t\t  // had (scriptRunEnd == run.end), which means (scriptRunStart == run.end)\n\t\t  // which is impossible due to the exit condition of the for loop. So we\n\t\t  // can be sure that scriptRunEnd > scriptRunStart.\n    \n\t\t  double letterSpace = 0.0;\n\t\t  double letterSpaceHalfLeft = 0.0;\n\t\t  double letterSpaceHalfRight = 0.0;\n    \n\t\t  if (ctx.paint.letterSpacing != 0.0 && isScriptOkForLetterspacing(new hb_script_t(script)))\n\t\t  {\n\t\t\tletterSpace = ctx.paint.letterSpacing * size * scaleX;\n\t\t\tif ((ctx.paint.paintFlags & LinearTextFlag) == 0)\n\t\t\t{\n\t\t\t  letterSpace = Math.Round(letterSpace);\n\t\t\t  letterSpaceHalfLeft = Math.Floor(letterSpace * 0.5);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t  letterSpaceHalfLeft = letterSpace * 0.5;\n\t\t\t}\n\t\t\tletterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;\n\t\t  }\n    \n\t\t  hb_buffer_clear_contents(buffer);\n\t\t  hb_buffer_set_script(buffer, script);\n\t\t  hb_buffer_set_direction(buffer, isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);\n\t\t  FontLanguages langList = FontLanguageListCache.getById(ctx.style.getLanguageListId());\n\t\t  if (langList.size() != 0)\n\t\t  {\n\t\t\tFontLanguage hbLanguage = langList[0];\n\t\t\tfor (int i = 0; i < langList.size(); ++i)\n\t\t\t{\n\t\t\t  if (langList[i].supportsHbScript(script))\n\t\t\t  {\n\t\t\t\thbLanguage = langList[i];\n\t\t\t\tbreak;\n\t\t\t  }\n\t\t\t}\n\t\t\thb_buffer_set_language(buffer, hbLanguage.getHbLanguage());\n\t\t  }\n    \n\t\t  uint clusterStart = addToHbBuffer(buffer, new UInt16(buf), start, count, bufSize, scriptRunStart, scriptRunEnd, ctx.paint.hyphenEdit, hbFont);\n    \n\t\t  hb_shape(hbFont, buffer, features.empty() ? null : features[0], features.size());\n\t\t  uint numGlyphs;\n\t\t  hb_glyph_info_t[] info = hb_buffer_get_glyph_infos(buffer, numGlyphs);\n\t\t  hb_glyph_position_t positions = hb_buffer_get_glyph_positions(buffer, null);\n    \n\t\t  // At this point in the code, the cluster values in the info buffer\n\t\t  // correspond to the input characters with some shift. The cluster value\n\t\t  // clusterStart corresponds to the first character passed to HarfBuzz,\n\t\t  // which is at buf[start + scriptRunStart] whose advance needs to be saved\n\t\t  // into mAdvances[scriptRunStart]. So cluster values need to be reduced by\n\t\t  // (clusterStart - scriptRunStart) to get converted to indices of\n\t\t  // mAdvances.\n\t\t  uint clusterOffset = clusterStart - scriptRunStart;\n    \n\t\t  if (numGlyphs != 0)\n\t\t  {\n\t\t\tmAdvances[info[0].cluster - clusterOffset] += letterSpaceHalfLeft;\n\t\t\tx += letterSpaceHalfLeft;\n\t\t  }\n\t\t  for (uint i = 0; i < numGlyphs; i++)\n\t\t  {\n\t#if VERBOSE_DEBUG\n\t\t\tALOGD(\"%d %d %d %d\", positions[i].x_advance, positions[i].y_advance, positions[i].x_offset, positions[i].y_offset);\n\t\t\tALOGD(\"DoLayout %u: %f; %d, %d\", info[i].codepoint, HBFixedToFloat(positions[i].x_advance), positions[i].x_offset, positions[i].y_offset);\n\t#endif\n\t\t\tif (i > 0 && info[i - 1].cluster != info[i].cluster)\n\t\t\t{\n\t\t\t  mAdvances[info[i - 1].cluster - clusterOffset] += letterSpaceHalfRight;\n\t\t\t  mAdvances[info[i].cluster - clusterOffset] += letterSpaceHalfLeft;\n\t\t\t  x += letterSpace;\n\t\t\t}\n    \n\t\t\thb_codepoint_t glyph_ix = info[i].codepoint;\n\t\t\tfloat xoff = HBFixedToFloat(positions[i].x_offset);\n\t\t\tfloat yoff = -HBFixedToFloat(positions[i].y_offset);\n\t\t\txoff += yoff * ctx.paint.skewX;\n\t\t\tLayoutGlyph glyph = new LayoutGlyph(font_ix, glyph_ix, x + xoff, y + yoff, (uint)(info[i].cluster - clusterOffset));\n\t\t\tmGlyphs.push_back(glyph);\n\t\t\tfloat xAdvance = HBFixedToFloat(positions[i].x_advance);\n\t\t\tif ((ctx.paint.paintFlags & LinearTextFlag) == 0)\n\t\t\t{\n\t\t\t  xAdvance = roundf(xAdvance);\n\t\t\t}\n\t\t\tMinikinRect glyphBounds = new MinikinRect();\n\t\t\thb_glyph_extents_t extents = new hb_glyph_extents_t();\n\t\t\tif (is_color_bitmap_font && hb_font_get_glyph_extents(hbFont, glyph_ix, extents))\n\t\t\t{\n\t\t\t  // Note that it is technically possible for a TrueType font to have\n\t\t\t  // outline and embedded bitmap at the same time. We ignore modified\n\t\t\t  // bbox of hinted outline glyphs in that case.\n\t\t\t  glyphBounds.mLeft = roundf(HBFixedToFloat(extents.x_bearing));\n\t\t\t  glyphBounds.mTop = roundf(HBFixedToFloat(-extents.y_bearing));\n\t\t\t  glyphBounds.mRight = roundf(HBFixedToFloat(extents.x_bearing + extents.width));\n\t\t\t  glyphBounds.mBottom = roundf(HBFixedToFloat(-extents.y_bearing - extents.height));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t  ctx.paint.font.GetBounds(glyphBounds, glyph_ix, ctx.paint);\n\t\t\t}\n\t\t\tglyphBounds.offset(x + xoff, y + yoff);\n\t\t\tmBounds.join(glyphBounds);\n\t\t\tif ((int)(info[i].cluster - clusterOffset) < count)\n\t\t\t{\n\t\t\t  mAdvances[info[i].cluster - clusterOffset] += xAdvance;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t  ALOGE(\"cluster %zu (start %zu) out of bounds of count %zu\", info[i].cluster - clusterOffset, start, count);\n\t\t\t}\n\t\t\tx += xAdvance;\n\t\t  }\n\t\t  if (numGlyphs != 0)\n\t\t  {\n\t\t\tmAdvances[info[numGlyphs - 1].cluster - clusterOffset] += letterSpaceHalfRight;\n\t\t\tx += letterSpaceHalfRight;\n\t\t  }\n\t\t}\n\t  }\n\t  mAdvance = x;\n\t}\n\n  // Append another layout (for example, cached value) into this one\n\tpublic void appendLayout(Layout src, int start, float extraAdvance)\n\t{\n\t  int[] fontMapStack = new int[16];\n\t//C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types:\n\t//ORIGINAL LINE: int* fontMap;\n\t  int fontMap;\n\t//C++ TO C# CONVERTER WARNING: This 'sizeof' ratio was replaced with a direct reference to the array length:\n\t//ORIGINAL LINE: if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0]))\n\t  if (src.mFaces.size() < fontMapStack.Length)\n\t  {\n\t\tfontMap = fontMapStack;\n\t  }\n\t  else\n\t  {\n\t\tfontMap = new int[src.mFaces.size()];\n\t  }\n\t  for (int i = 0; i < src.mFaces.size(); i++)\n\t  {\n\t\tint font_ix = findFace(src.mFaces[i], null);\n\t\tfontMap[i] = font_ix;\n\t  }\n\t  // LibTxt: Changed x0 from int to float to prevent rounding that causes text\n\t  // jitter.\n\t  float x0 = mAdvance;\n\t  for (int i = 0; i < src.mGlyphs.size(); i++)\n\t  {\n\t\tLayoutGlyph srcGlyph = src.mGlyphs[i];\n\t\tint font_ix = fontMap[srcGlyph.font_ix];\n\t\tuint glyph_id = srcGlyph.glyph_id;\n\t\tfloat x = x0 + srcGlyph.x;\n\t\tfloat y = srcGlyph.y;\n\t\tLayoutGlyph glyph = new LayoutGlyph(font_ix, glyph_id, x, y, (uint)(srcGlyph.cluster + start));\n\t\tmGlyphs.push_back(glyph);\n\t  }\n\t  for (int i = 0; i < src.mAdvances.size(); i++)\n\t  {\n\t\tmAdvances[i + start] = src.mAdvances[i];\n\t\tif (i == 0)\n\t\t{\n\t\t  mAdvances[i + start] += extraAdvance;\n\t\t}\n\t  }\n\t  MinikinRect srcBounds = new MinikinRect(src.mBounds);\n\t  srcBounds.offset(x0, 0);\n\t  mBounds.join(srcBounds);\n\t  mAdvance += src.mAdvance + extraAdvance;\n    \n\t  if (fontMap != fontMapStack)\n\t  {\n\t\tfontMap = null;\n\t  }\n\t}\n\n  private List<LayoutGlyph> mGlyphs = new List<LayoutGlyph>();\n  private List<float> mAdvances = new List<float>();\n\n  private List<FakedFont> mFaces = new List<FakedFont>();\n  private float mAdvance;\n  private MinikinRect mBounds = new MinikinRect();\n}\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/LayoutUtils.cs",
    "content": "﻿/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/LineBreaker.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n\n\nnamespace minikin\n{\n\n\n\n\n\n// Ordinarily, this method measures the text in the range given. However, when\n// paint is nullptr, it assumes the widths have already been calculated and\n// stored in the width buffer. This method finds the candidate word breaks\n// (using the ICU break iterator) and sends them to addCandidate.\n\n// add a word break (possibly for a hyphenated fragment), and add desperate\n// breaks if needed (ie when word exceeds current line width)\n\n// Helper method for addCandidate()\n\n// TODO performance: could avoid populating mCandidates if greedy only\n\n\n\n// Get the width of a space. May return 0 if there are no spaces.\n// Note: if there are multiple different widths for spaces (for example, because\n// of mixing of fonts), it's only guaranteed to pick one.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float LineBreaker::getSpaceWidth() const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float LineBreaker::currentLineWidth() const\n\n\n// Follow \"prev\" links in mCandidates array, and copy to result arrays.\n\n\n\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/LineBreaker.h.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A module for breaking paragraphs into lines, supporting high quality\n * hyphenation and justification.\n */\n\n\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/brkiter.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/locid.h\"\n\nnamespace minikin\n{\n\npublic enum BreakStrategy\n{\n  kBreakStrategy_Greedy = 0,\n  kBreakStrategy_HighQuality = 1,\n  kBreakStrategy_Balanced = 2\n}\n\npublic enum HyphenationFrequency\n{\n  kHyphenationFrequency_None = 0,\n  kHyphenationFrequency_Normal = 1,\n  kHyphenationFrequency_Full = 2\n}\n\n// TODO: want to generalize to be able to handle array of line widths\npublic class LineWidths\n{\n  public void setWidths(float firstWidth, int firstWidthLineCount, float restWidth)\n  {\n\tmFirstWidth = firstWidth;\n\tmFirstWidthLineCount = firstWidthLineCount;\n\tmRestWidth = restWidth;\n  }\n  public void setIndents(List<float> indents)\n  {\n\t  mIndents = new List<float>(indents);\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool isConstant() const\n  public bool isConstant()\n  {\n\t// technically mFirstWidthLineCount == 0 would count too, but doesn't\n\t// actually happen\n\treturn mRestWidth == mFirstWidth && mIndents.Count == 0;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getLineWidth(int line) const\n  public float getLineWidth(int line)\n  {\n\tfloat width = (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;\n\tif (mIndents.Count > 0)\n\t{\n\t  if ((int)line < mIndents.Count)\n\t  {\n\t\twidth -= mIndents[line];\n\t  }\n\t  else\n\t  {\n\t\twidth -= mIndents[mIndents.Count - 1];\n\t  }\n\t}\n\treturn width;\n  }\n  public void clear()\n  {\n\t  mIndents.Clear();\n  }\n\n  private float mFirstWidth;\n  private int mFirstWidthLineCount;\n  private float mRestWidth;\n  private List<float> mIndents = new List<float>();\n}\n\npublic class TabStops\n{\n  public void set(int stops, int nStops, int tabWidth)\n  {\n\tif (stops != null)\n\t{\n\t  mStops.assign(stops, stops + nStops);\n\t}\n\telse\n\t{\n\t  mStops.Clear();\n\t}\n\tmTabWidth = tabWidth;\n  }\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float nextTab(float widthSoFar) const\n  public float nextTab(float widthSoFar)\n  {\n\tfor (int i = 0; i < mStops.Count; i++)\n\t{\n\t  if (mStops[i] > widthSoFar)\n\t  {\n\t\treturn mStops[i];\n\t  }\n\t}\n\treturn Math.Floor(widthSoFar / mTabWidth + 1) * mTabWidth;\n  }\n\n  private List<int> mStops = new List<int>();\n  private int mTabWidth;\n}\n\npublic class LineBreaker\n{\n  public const int kTab_Shift = 29; // keep synchronized with TAB_MASK in StaticLayout.java\n\n  // Note: Locale persists across multiple invocations (it is not cleaned up by\n  // finish()), explicitly to avoid the cost of creating ICU BreakIterator\n  // objects. It should always be set on the first invocation, but callers are\n  // encouraged not to call again unless locale has actually changed. That logic\n  // could be here but it's better for performance that it's upstream because of\n  // the cost of constructing and comparing the ICU Locale object.\n  // Note: caller is responsible for managing lifetime of hyphenator\n\tpublic void setLocale(icu.Locale locale, Hyphenator hyphenator)\n\t{\n\t  mWordBreaker.setLocale(locale);\n\t  mLocale = locale;\n\t  mHyphenator = hyphenator;\n\t}\n\n  public void resize(int size)\n  {\n\tmTextBuf.Resize(size);\n\tmCharWidths.Resize(size);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int size() const\n  public int size()\n  {\n\t  return mTextBuf.Count;\n  }\n\n  public UInt16 buffer()\n  {\n\t  return mTextBuf.data();\n  }\n\n//C++ TO C# CONVERTER WARNING: C# has no equivalent to methods returning pointers to value types:\n//ORIGINAL LINE: float* charWidths()\n  public float charWidths()\n  {\n\t  return mCharWidths.data();\n  }\n\n  // set text to current contents of buffer\n\tpublic void setText()\n\t{\n\t  mWordBreaker.setText(mTextBuf.data(), mTextBuf.size());\n    \n\t  // handle initial break here because addStyleRun may never be called\n\t  mWordBreaker.next();\n\t  mCandidates.clear();\n\t  Candidate cand = new Candidate(0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, HyphenationType.DONT_BREAK);\n\t  mCandidates.push_back(cand);\n    \n\t  // reset greedy breaker state\n\t  mBreaks.clear();\n\t  mWidths.clear();\n\t  mFlags.clear();\n\t  mLastBreak = 0;\n\t  mBestBreak = 0;\n\t  mBestScore = SCORE_INFTY;\n\t  mPreBreak = 0;\n\t  mLastHyphenation = HyphenEdit.NO_EDIT;\n\t  mFirstTabIndex = INT_MAX;\n\t  mSpaceCount = 0;\n\t}\n\n\tpublic void setLineWidths(float firstWidth, int firstWidthLineCount, float restWidth)\n\t{\n\t  mLineWidths.setWidths(firstWidth, firstWidthLineCount, restWidth);\n\t}\n\n\tpublic void setIndents(List<float> indents)\n\t{\n\t  mLineWidths.setIndents(indents);\n\t}\n\n  public void setTabStops(int stops, int nStops, int tabWidth)\n  {\n\tmTabStops.set(stops, nStops, tabWidth);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: BreakStrategy getStrategy() const\n  public BreakStrategy getStrategy()\n  {\n\t  return mStrategy;\n  }\n\n  public void setStrategy(BreakStrategy strategy)\n  {\n\t  mStrategy = strategy;\n  }\n\n  public void setJustified(bool justified)\n  {\n\t  mJustified = justified;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: HyphenationFrequency getHyphenationFrequency() const\n  public HyphenationFrequency getHyphenationFrequency()\n  {\n\treturn mHyphenationFrequency;\n  }\n\n  public void setHyphenationFrequency(HyphenationFrequency frequency)\n  {\n\tmHyphenationFrequency = frequency;\n  }\n\n  // TODO: this class is actually fairly close to being general and not tied to\n  // using Minikin to do the shaping of the strings. The main thing that would\n  // need to be changed is having some kind of callback (or virtual class, or\n  // maybe even template), which could easily be instantiated with Minikin's\n  // Layout. Future work for when needed.\n\tpublic float addStyleRun(MinikinPaint paint, FontCollection typeface, FontStyle style, int start, int end, bool isRtl)\n\t{\n\t  float width = 0.0f;\n\t  int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;\n    \n\t  float hyphenPenalty = 0.0F;\n\t  if (paint != null)\n\t  {\n\t\twidth = Layout.measureText(mTextBuf.data(), start, end - start, mTextBuf.size(), bidiFlags, style, paint, typeface, mCharWidths.data() + start);\n    \n\t\t// a heuristic that seems to perform well\n\t\thyphenPenalty = 0.5 * paint.size * paint.scaleX * mLineWidths.getLineWidth(0);\n\t\tif (mHyphenationFrequency == kHyphenationFrequency_Normal)\n\t\t{\n\t\t  hyphenPenalty *= 4.0; // TODO: Replace with a better value after some testing\n\t\t}\n    \n\t\tif (mJustified)\n\t\t{\n\t\t  // Make hyphenation more aggressive for fully justified text (so that\n\t\t  // \"normal\" in justified mode is the same as \"full\" in ragged-right).\n\t\t  hyphenPenalty *= 0.25;\n\t\t}\n\t\telse\n\t\t{\n\t\t  // Line penalty is zero for justified text.\n\t\t  mLinePenalty = Math.Max(mLinePenalty, hyphenPenalty * LINE_PENALTY_MULTIPLIER);\n\t\t}\n\t  }\n    \n\t  int current = (int)mWordBreaker.current();\n\t  int afterWord = start;\n\t  int lastBreak = start;\n\t  ParaWidth lastBreakWidth = mWidth;\n\t  ParaWidth postBreak = mWidth;\n\t  int postSpaceCount = mSpaceCount;\n\t  for (int i = start; i < end; i++)\n\t  {\n\t\tUInt16 c = mTextBuf[i];\n\t\tif (c == CHAR_TAB)\n\t\t{\n\t\t  mWidth = mPreBreak + mTabStops.nextTab(mWidth - mPreBreak);\n\t\t  if (mFirstTabIndex == INT_MAX)\n\t\t  {\n\t\t\tmFirstTabIndex = (int)i;\n\t\t  }\n\t\t  // fall back to greedy; other modes don't know how to deal with tabs\n\t\t  mStrategy = kBreakStrategy_Greedy;\n\t\t}\n\t\telse\n\t\t{\n\t\t  if (isWordSpace(new UInt16(c)))\n\t\t  {\n\t\t\tmSpaceCount += 1;\n\t\t  }\n\t\t  mWidth += mCharWidths[i];\n\t\t  if (!isLineEndSpace(new UInt16(c)))\n\t\t  {\n\t\t\tpostBreak = mWidth;\n\t\t\tpostSpaceCount = mSpaceCount;\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: afterWord = i + 1;\n\t\t\tafterWord.CopyFrom(i + 1);\n\t\t  }\n\t\t}\n\t\tif (i + 1 == current != null)\n\t\t{\n\t\t  int wordStart = mWordBreaker.wordStart();\n\t\t  int wordEnd = mWordBreaker.wordEnd();\n\t\t  if (paint != null && mHyphenator != null && mHyphenationFrequency != kHyphenationFrequency_None && wordStart >= start != null && wordEnd > wordStart && wordEnd - wordStart <= LONGEST_HYPHENATED_WORD)\n\t\t  {\n\t\t\tmHyphenator.hyphenate(mHyphBuf, mTextBuf[wordStart], wordEnd - wordStart, mLocale);\n\t#if VERBOSE_DEBUG\n\t\t\tstring hyphenatedString;\n\t\t\tfor (int j = wordStart; j < wordEnd; j++)\n\t\t\t{\n\t\t\t  if (mHyphBuf[j - wordStart] == HyphenationType.BREAK_AND_INSERT_HYPHEN)\n\t\t\t  {\n\t\t\t\thyphenatedString.push_back('-');\n\t\t\t  }\n\t\t\t  // Note: only works with ASCII, should do UTF-8 conversion here\n\t\t\t  hyphenatedString.push_back(buffer()[j]);\n\t\t\t}\n\t\t\tALOGD(\"hyphenated string: %s\", hyphenatedString);\n\t#endif\n    \n\t\t\t// measure hyphenated substrings\n\t\t\tfor (int j = wordStart; j < wordEnd; j++)\n\t\t\t{\n\t\t\t  HyphenationType hyph = mHyphBuf[j - wordStart];\n\t\t\t  if (hyph != HyphenationType.DONT_BREAK)\n\t\t\t  {\n\t\t\t\tpaint.hyphenEdit = HyphenEdit.editForThisLine(hyph);\n\t\t\t\tfloat firstPartWidth = Layout.measureText(mTextBuf.data(), lastBreak, j - lastBreak, mTextBuf.size(), bidiFlags, style, paint, typeface, null);\n\t\t\t\tParaWidth hyphPostBreak = lastBreakWidth + firstPartWidth;\n    \n\t\t\t\tpaint.hyphenEdit = HyphenEdit.editForNextLine(hyph);\n\t\t\t\tfloat secondPartWidth = Layout.measureText(mTextBuf.data(), j, afterWord - j, mTextBuf.size(), bidiFlags, style, paint, typeface, null);\n\t\t\t\tParaWidth hyphPreBreak = postBreak - secondPartWidth;\n    \n\t\t\t\taddWordBreak(j, hyphPreBreak, hyphPostBreak, postSpaceCount, postSpaceCount, hyphenPenalty, hyph);\n    \n\t\t\t\tpaint.hyphenEdit = HyphenEdit.NO_EDIT;\n\t\t\t  }\n\t\t\t}\n\t\t  }\n    \n\t\t  // Skip break for zero-width characters inside replacement span\n\t\t  if (paint != null || current == end || mCharWidths[current] > 0)\n\t\t  {\n\t\t\tfloat penalty = hyphenPenalty * mWordBreaker.breakBadness();\n\t\t\taddWordBreak(current, mWidth, postBreak, mSpaceCount, postSpaceCount, penalty, HyphenationType.DONT_BREAK);\n\t\t  }\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: lastBreak = current;\n\t\t  lastBreak.CopyFrom(current);\n\t\t  lastBreakWidth = mWidth;\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: current = (int)mWordBreaker.next();\n\t\t  current.CopyFrom((int)mWordBreaker.next());\n\t\t}\n\t  }\n    \n\t  return width;\n\t}\n\n\tpublic void addReplacement(int start, int end, float width)\n\t{\n\t  mCharWidths[start] = width;\n\t  std::fill(mCharWidths[start + 1], mCharWidths[end], 0.0f);\n\t  addStyleRun(null, null, FontStyle(), start, end, false);\n\t}\n\n\tpublic int computeBreaks()\n\t{\n\t  if (mStrategy == kBreakStrategy_Greedy)\n\t  {\n\t\tcomputeBreaksGreedy();\n\t  }\n\t  else\n\t  {\n\t\tcomputeBreaksOptimal(mLineWidths.isConstant());\n\t  }\n\t  return mBreaks.size();\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const int* getBreaks() const\n//C++ TO C# CONVERTER WARNING: C# has no equivalent to methods returning pointers to value types:\n  public int getBreaks()\n  {\n\t  return mBreaks.data();\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const float* getWidths() const\n//C++ TO C# CONVERTER WARNING: C# has no equivalent to methods returning pointers to value types:\n  public float getWidths()\n  {\n\t  return mWidths.data();\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const int* getFlags() const\n//C++ TO C# CONVERTER WARNING: C# has no equivalent to methods returning pointers to value types:\n  public int getFlags()\n  {\n\t  return mFlags.data();\n  }\n\n\tpublic void finish()\n\t{\n\t  mWordBreaker.finish();\n\t  mWidth = 0;\n\t  mLineWidths.clear();\n\t  mCandidates.clear();\n\t  mBreaks.clear();\n\t  mWidths.clear();\n\t  mFlags.clear();\n\t  if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN)\n\t  {\n\t\tmTextBuf.clear();\n\t\tmTextBuf.shrink_to_fit();\n\t\tmCharWidths.clear();\n\t\tmCharWidths.shrink_to_fit();\n\t\tmHyphBuf.clear();\n\t\tmHyphBuf.shrink_to_fit();\n\t\tmCandidates.shrink_to_fit();\n\t\tmBreaks.shrink_to_fit();\n\t\tmWidths.shrink_to_fit();\n\t\tmFlags.shrink_to_fit();\n\t  }\n\t  mStrategy = kBreakStrategy_Greedy;\n\t  mHyphenationFrequency = kHyphenationFrequency_Normal;\n\t  mLinePenalty = 0.0f;\n\t  mJustified = false;\n\t}\n\n  // ParaWidth is used to hold cumulative width from beginning of paragraph.\n  // Note that for very large paragraphs, accuracy could degrade using only\n  // 32-bit float. Note however that float is used extensively on the Java side\n  // for this. This is a typedef so that we can easily change it based on\n  // performance/accuracy tradeoff.\n\n  // A single candidate break\n  private class Candidate\n  {\n\tpublic int offset = new int(); // offset to text buffer, in code units\n\tpublic int prev = new int(); // index to previous break\n\tpublic ParaWidth preBreak = new ParaWidth(); // width of text until this point, if we decide to not\n\t\t\t\t\t\t  // break here\n\tpublic ParaWidth postBreak = new ParaWidth(); // width of text until this point, if we decide to\n\t\t\t\t\t\t  // break here\n\tpublic float penalty; // penalty of this break (for example, hyphen penalty)\n\tpublic float score; // best score found for this break\n\tpublic int lineNumber = new int(); // only updated for non-constant line widths\n\tpublic int preSpaceCount = new int(); // preceding space count before breaking\n\tpublic int postSpaceCount = new int(); // preceding space count after breaking\n\tpublic HyphenationType hyphenType;\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float currentLineWidth() const;\n\tpublic float currentLineWidth()\n\t{\n\t  return mLineWidths.getLineWidth(mBreaks.size());\n\t}\n\n\tpublic void addWordBreak(int offset, ParaWidth preBreak, ParaWidth postBreak, int preSpaceCount, int postSpaceCount, float penalty, HyphenationType hyph)\n\t{\n\t  Candidate cand = new Candidate();\n\t  ParaWidth width = mCandidates.back().preBreak;\n\t  if (postBreak - width > currentLineWidth() != null)\n\t  {\n\t\t// Add desperate breaks.\n\t\t// Note: these breaks are based on the shaping of the (non-broken) original\n\t\t// text; they are imprecise especially in the presence of kerning,\n\t\t// ligatures, and Arabic shaping.\n\t\tint i = mCandidates.back().offset;\n\t\twidth += mCharWidths[i++];\n\t\tfor (; i < offset; i++)\n\t\t{\n\t\t  float w = mCharWidths[i];\n\t\t  if (w > 0F)\n\t\t  {\n\t\t\tcand.offset = i;\n\t\t\tcand.preBreak = width;\n\t\t\tcand.postBreak = width;\n\t\t\t// postSpaceCount doesn't include trailing spaces\n\t\t\tcand.preSpaceCount = postSpaceCount;\n\t\t\tcand.postSpaceCount = postSpaceCount;\n\t\t\tcand.penalty = SCORE_DESPERATE;\n\t\t\tcand.hyphenType = HyphenationType.BREAK_AND_DONT_INSERT_HYPHEN;\n\t#if VERBOSE_DEBUG\n\t\t\tALOGD(\"desperate cand: %zd %g:%g\", mCandidates.size(), cand.postBreak, cand.preBreak);\n\t#endif\n\t\t\taddCandidate(cand);\n\t\t\twidth += w;\n\t\t  }\n\t\t}\n\t  }\n    \n\t  cand.offset = offset;\n\t  cand.preBreak = preBreak;\n\t  cand.postBreak = postBreak;\n\t  cand.penalty = penalty;\n\t  cand.preSpaceCount = preSpaceCount;\n\t  cand.postSpaceCount = postSpaceCount;\n\t  cand.hyphenType = hyph;\n\t#if VERBOSE_DEBUG\n\t  ALOGD(\"cand: %zd %g:%g\", mCandidates.size(), cand.postBreak, cand.preBreak);\n\t#endif\n\t  addCandidate(cand);\n\t}\n\n\tpublic void addCandidate(Candidate cand)\n\t{\n\t  int candIndex = mCandidates.size();\n\t  mCandidates.push_back(cand);\n    \n\t  // mLastBreak is the index of the last line break we decided to do in\n\t  // mCandidates, and mPreBreak is its preBreak value. mBestBreak is the index\n\t  // of the best line breaking candidate we have found since then, and\n\t  // mBestScore is its penalty.\n\t  if (cand.postBreak - mPreBreak > currentLineWidth())\n\t  {\n\t\t// This break would create an overfull line, pick the best break and break\n\t\t// there (greedy)\n\t\tif (mBestBreak == mLastBreak)\n\t\t{\n\t\t  // No good break has been found since last break. Break here.\n\t\t  mBestBreak = candIndex;\n\t\t}\n\t\tpushGreedyBreak();\n\t  }\n    \n\t  while (mLastBreak != candIndex && cand.postBreak - mPreBreak > currentLineWidth())\n\t  {\n\t\t// We should rarely come here. But if we are here, we have broken the line,\n\t\t// but the remaining part still doesn't fit. We now need to break at the\n\t\t// second best place after the last break, but we have not kept that\n\t\t// information, so we need to go back and find it.\n\t\t//\n\t\t// In some really rare cases, postBreak - preBreak of a candidate itself may\n\t\t// be over the current line width. We protect ourselves against an infinite\n\t\t// loop in that case by checking that we have not broken the line at this\n\t\t// candidate already.\n\t\tfor (int i = mLastBreak + 1; i < candIndex; i++)\n\t\t{\n\t\t  float penalty = mCandidates[i].penalty;\n\t\t  if (penalty <= mBestScore)\n\t\t  {\n\t\t\tmBestBreak = i;\n\t\t\tmBestScore = penalty;\n\t\t  }\n\t\t}\n\t\tif (mBestBreak == mLastBreak)\n\t\t{\n\t\t  // We didn't find anything good. Break here.\n\t\t  mBestBreak = candIndex;\n\t\t}\n\t\tpushGreedyBreak();\n\t  }\n    \n\t  if (cand.penalty <= mBestScore)\n\t  {\n\t\tmBestBreak = candIndex;\n\t\tmBestScore = cand.penalty;\n\t  }\n\t}\n\tpublic void pushGreedyBreak()\n\t{\n\t  Candidate bestCandidate = mCandidates[mBestBreak];\n\t  pushBreak(bestCandidate.offset, bestCandidate.postBreak - mPreBreak, mLastHyphenation | HyphenEdit.editForThisLine(bestCandidate.hyphenType));\n\t  mBestScore = SCORE_INFTY;\n\t#if VERBOSE_DEBUG\n\t  ALOGD(\"break: %d %g\", mBreaks.back(), mWidths.back());\n\t#endif\n\t  mLastBreak = mBestBreak;\n\t  mPreBreak = bestCandidate.preBreak;\n\t  mLastHyphenation = HyphenEdit.editForNextLine(bestCandidate.hyphenType);\n\t}\n\n  // push an actual break to the output. Takes care of setting flags for tab\n\tpublic void pushBreak(int offset, float width, byte hyphenEdit)\n\t{\n\t  mBreaks.push_back(offset);\n\t  mWidths.push_back(width);\n\t  int flags = (mFirstTabIndex < mBreaks.back()) << kTab_Shift;\n\t  flags |= hyphenEdit;\n\t  mFlags.push_back(flags);\n\t  mFirstTabIndex = INT_MAX;\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: float getSpaceWidth() const;\n\tpublic float getSpaceWidth()\n\t{\n\t  for (int i = 0; i < mTextBuf.size(); i++)\n\t  {\n\t\tif (isWordSpace(mTextBuf[i]))\n\t\t{\n\t\t  return mCharWidths[i];\n\t\t}\n\t  }\n\t  return 0.0f;\n\t}\n\n\tpublic void computeBreaksGreedy()\n\t{\n\t  // All breaks but the last have been added in addCandidate already.\n\t  int nCand = mCandidates.size();\n\t  if (nCand > 0 && (nCand == 1 || mLastBreak != nCand - 1))\n\t  {\n\t\tpushBreak(mCandidates[nCand - 1].offset, mCandidates[nCand - 1].postBreak - mPreBreak, mLastHyphenation);\n\t\t// don't need to update mBestScore, because we're done\n\t#if VERBOSE_DEBUG\n\t\tALOGD(\"final break: %d %g\", mBreaks.back(), mWidths.back());\n\t#endif\n\t  }\n\t}\n\n\tpublic void computeBreaksOptimal(bool isRectangle)\n\t{\n\t  int active = 0;\n\t  int nCand = mCandidates.size();\n\t  float width = mLineWidths.getLineWidth(0);\n\t  float shortLineFactor = mJustified ? 0.75f : 0.5f;\n\t  float maxShrink = mJustified ? SHRINKABILITY * getSpaceWidth() : 0.0f;\n    \n\t  // \"i\" iterates through candidates for the end of the line.\n\t  for (int i = 1; i < nCand; i++)\n\t  {\n\t\tbool atEnd = i == nCand - 1;\n\t\tfloat best = SCORE_INFTY;\n\t\tint bestPrev = 0;\n\t\tint lineNumberLast = 0;\n    \n\t\tif (!isRectangle)\n\t\t{\n\t\t  int lineNumberLast = mCandidates[active].lineNumber;\n\t\t  width = mLineWidths.getLineWidth(lineNumberLast);\n\t\t}\n\t\tParaWidth leftEdge = mCandidates[i].postBreak - width;\n\t\tfloat bestHope = 0F;\n    \n\t\t// \"j\" iterates through candidates for the beginning of the line.\n\t\tfor (int j = active; j < i; j++)\n\t\t{\n\t\t  if (!isRectangle)\n\t\t  {\n\t\t\tint lineNumber = mCandidates[j].lineNumber;\n\t\t\tif (lineNumber != lineNumberLast)\n\t\t\t{\n\t\t\t  float widthNew = mLineWidths.getLineWidth(lineNumber);\n\t\t\t  if (widthNew != width)\n\t\t\t  {\n\t\t\t\tleftEdge = mCandidates[i].postBreak - width;\n\t\t\t\tbestHope = 0F;\n\t\t\t\twidth = widthNew;\n\t\t\t  }\n\t\t\t  lineNumberLast = lineNumber;\n\t\t\t}\n\t\t  }\n\t\t  float jScore = mCandidates[j].score;\n\t\t  if (jScore + bestHope >= best)\n\t\t  {\n\t\t\tcontinue;\n\t\t  }\n\t\t  float delta = mCandidates[j].preBreak - leftEdge;\n    \n\t\t  // compute width score for line\n    \n\t\t  // Note: the \"bestHope\" optimization makes the assumption that, when delta\n\t\t  // is non-negative, widthScore will increase monotonically as successive\n\t\t  // candidate breaks are considered.\n\t\t  float widthScore = 0.0f;\n\t\t  float additionalPenalty = 0.0f;\n\t\t  if ((atEnd || !mJustified) && delta < 0F)\n\t\t  {\n\t\t\twidthScore = SCORE_OVERFULL;\n\t\t  }\n\t\t  else if (atEnd && mStrategy != kBreakStrategy_Balanced)\n\t\t  {\n\t\t\t// increase penalty for hyphen on last line\n\t\t\tadditionalPenalty = LAST_LINE_PENALTY_MULTIPLIER * mCandidates[j].penalty;\n\t\t\t// Penalize very short (< 1 - shortLineFactor of total width) lines.\n\t\t\tfloat underfill = delta - shortLineFactor * width;\n\t\t\twidthScore = underfill > 0F ? underfill * underfill : 0;\n\t\t  }\n\t\t  else\n\t\t  {\n\t\t\twidthScore = delta * delta;\n\t\t\tif (delta < 0F)\n\t\t\t{\n\t\t\t  if (-delta < maxShrink * (mCandidates[i].postSpaceCount - mCandidates[j].preSpaceCount))\n\t\t\t  {\n\t\t\t\twidthScore *= SHRINK_PENALTY_MULTIPLIER;\n\t\t\t  }\n\t\t\t  else\n\t\t\t  {\n\t\t\t\twidthScore = SCORE_OVERFULL;\n\t\t\t  }\n\t\t\t}\n\t\t  }\n    \n\t\t  if (delta < 0F)\n\t\t  {\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: active = j + 1;\n\t\t\tactive.CopyFrom(j + 1);\n\t\t  }\n\t\t  else\n\t\t  {\n\t\t\tbestHope = widthScore;\n\t\t  }\n    \n\t\t  float score = jScore + widthScore + additionalPenalty;\n\t\t  if (score <= best)\n\t\t  {\n\t\t\tbest = score;\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: bestPrev = j;\n\t\t\tbestPrev.CopyFrom(j);\n\t\t  }\n\t\t}\n\t\tmCandidates[i].score = best + mCandidates[i].penalty + mLinePenalty;\n\t\tmCandidates[i].prev = bestPrev;\n\t\tmCandidates[i].lineNumber = mCandidates[bestPrev].lineNumber + 1;\n\t#if VERBOSE_DEBUG\n\t\tALOGD(\"break %zd: score=%g, prev=%zd\", i, mCandidates[i].score, mCandidates[i].prev);\n\t#endif\n\t  }\n\t  finishBreaksOptimal();\n\t}\n\n\tpublic void finishBreaksOptimal()\n\t{\n\t  // clear existing greedy break result\n\t  mBreaks.clear();\n\t  mWidths.clear();\n\t  mFlags.clear();\n\t  int nCand = mCandidates.size();\n\t  int prev = new int();\n\t  for (int i = nCand - 1; i > 0; i = prev)\n\t  {\n\t\tprev = mCandidates[i].prev;\n\t\tmBreaks.push_back(mCandidates[i].offset);\n\t\tmWidths.push_back(mCandidates[i].postBreak - mCandidates[prev].preBreak);\n\t\tint flags = HyphenEdit.editForThisLine(mCandidates[i].hyphenType);\n\t\tif (prev > 0)\n\t\t{\n\t\t  flags |= HyphenEdit.editForNextLine(mCandidates[prev].hyphenType);\n\t\t}\n\t\tmFlags.push_back(flags);\n\t  }\n\t  std::reverse(mBreaks.begin(), mBreaks.end());\n\t  std::reverse(mWidths.begin(), mWidths.end());\n\t  std::reverse(mFlags.begin(), mFlags.end());\n\t}\n\n  private WordBreaker mWordBreaker = new WordBreaker();\n  private icu.Locale mLocale = new icu.Locale();\n  private List<UInt16> mTextBuf = new List<UInt16>();\n  private List<float> mCharWidths = new List<float>();\n\n  private Hyphenator mHyphenator;\n  private List<HyphenationType> mHyphBuf = new List<HyphenationType>();\n\n  // layout parameters\n  private BreakStrategy mStrategy = BreakStrategy.kBreakStrategy_Greedy;\n  private HyphenationFrequency mHyphenationFrequency = HyphenationFrequency.kHyphenationFrequency_Normal;\n  private bool mJustified;\n  private LineWidths mLineWidths = new LineWidths();\n  private TabStops mTabStops = new TabStops();\n\n  // result of line breaking\n  private List<int> mBreaks = new List<int>();\n  private List<float> mWidths = new List<float>();\n  private List<int> mFlags = new List<int>();\n\n  private double mWidth = 0;\n  private List<Candidate> mCandidates = new List<Candidate>();\n  private float mLinePenalty = 0.0f;\n\n  // the following are state for greedy breaker (updated while adding style\n  // runs)\n  private int mLastBreak = new int();\n  private int mBestBreak = new int();\n  private float mBestScore;\n  private double mPreBreak; // prebreak of last break\n  private uint mLastHyphenation = new uint(); // hyphen edit of last break kept for next line\n  private int mFirstTabIndex;\n  private int mSpaceCount = new int();\n}\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/Measurement.cs",
    "content": "﻿/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/Measurement.h.cs",
    "content": "﻿/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/MinikinFont.cs",
    "content": "﻿/*\n * Copyright (C) 2016 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/MinikinFont.h.cs",
    "content": "﻿using System.Collections.Generic;\nusing System;\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n// An abstraction for platform fonts, allowing Minikin to be used with\n// multiple actual implementations of fonts.\n\nnamespace minikin\n{\n\n    //C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n    //class MinikinFont;\n\n    // Possibly move into own .h file?\n    // Note: if you add a field here, either add it to LayoutCacheKey or to\n    // skipCache()\n    public class MinikinPaint\n    {\n        public MinikinPaint()\n        {\n            this.font = null;\n            this.size = 0F;\n            this.scaleX = 0F;\n            this.skewX = 0F;\n            this.letterSpacing = 0F;\n            this.wordSpacing = 0F;\n            this.paintFlags = 0;\n            this.fakery = new FontFakery();\n            this.hyphenEdit = new HyphenEdit();\n            this.fontFeatureSettings = string.Empty;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool skipCache() const\n        public bool skipCache()\n        {\n            return !string.IsNullOrEmpty(fontFeatureSettings);\n        }\n\n        public MinikinFont font;\n        public float size;\n        public float scaleX;\n        public float skewX;\n        public float letterSpacing;\n        public float wordSpacing;\n        public uint paintFlags = new uint();\n        public FontFakery fakery = new FontFakery();\n        public HyphenEdit hyphenEdit = new HyphenEdit();\n        public string fontFeatureSettings;\n    }\n\n    // Only a few flags affect layout, but those that do should have values\n    // consistent with Android's paint flags.\n    public enum MinikinPaintFlags\n    {\n        LinearTextFlag = 0x40,\n    }\n\n    public class MinikinRect\n    {\n        public float mLeft;\n        public float mTop;\n        public float mRight;\n        public float mBottom;\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool isEmpty() const\n        public bool isEmpty()\n        {\n            return mLeft == mRight || mTop == mBottom;\n        }\n        public void set(MinikinRect r)\n        {\n            mLeft = r.mLeft;\n            mTop = r.mTop;\n            mRight = r.mRight;\n            mBottom = r.mBottom;\n        }\n        public void offset(float dx, float dy)\n        {\n            mLeft += dx;\n            mTop += dy;\n            mRight += dx;\n            mBottom += dy;\n        }\n        public void setEmpty()\n        {\n            mLeft = mTop = mRight = mBottom = 0F;\n        }\n        public void join(MinikinRect r)\n        {\n            if (isEmpty())\n            {\n                set(r);\n            }\n            else if (!r.isEmpty())\n            {\n                mLeft = Math.Min(mLeft, r.mLeft);\n                mTop = Math.Min(mTop, r.mTop);\n                mRight = Math.Max(mRight, r.mRight);\n                mBottom = Math.Max(mBottom, r.mBottom);\n            }\n        }\n    }\n\n    // Callback for freeing data\n    public delegate void MinikinDestroyFunc(object data);\n\n    public abstract class MinikinFont : System.IDisposable\n    {\n        public MinikinFont(int uniqueId)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.mUniqueId = uniqueId;\n            this.mUniqueId = uniqueId;\n        }\n\n        public void Dispose()\n        {\n            //var _l = new std::lock_guard<std::recursive_mutex>(gMinikinLock);\n            //purgeHbFontLocked(this);\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: virtual float GetHorizontalAdvance(uint glyph_id, const MinikinPaint& paint) const = 0;\n        public abstract float GetHorizontalAdvance(uint glyph_id, MinikinPaint paint);\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: virtual void GetBounds(MinikinRect* bounds, uint glyph_id, const MinikinPaint& paint) const = 0;\n        public abstract void GetBounds(MinikinRect bounds, uint glyph_id, MinikinPaint paint);\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: virtual HarfBuzzSharp.Face* CreateHarfBuzzFace() const\n        public virtual HarfBuzzSharp.Face CreateHarfBuzzFace()\n        {\n            return null;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: virtual const ClassicVector<minikin::FontVariation>& GetAxes() const = 0;\n        public abstract List<minikin.FontVariation> GetAxes();\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: virtual MinikinFont createFontWithVariation(const ClassicVector<FontVariation>&) const\n        public virtual MinikinFont createFontWithVariation(List<FontVariation> UnnamedParameter)\n        {\n            return null;\n        }\n\n        public static uint MakeTag(char c1, char c2, char c3, char c4)\n        {\n            return ((uint)c1 << 24) | ((uint)c2 << 16) | ((uint)c3 << 8) | (uint)c4;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int GetUniqueId() const\n        public int GetUniqueId()\n        {\n            return mUniqueId;\n        }\n\n        private readonly int mUniqueId = new int();\n    }\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/MinikinInternal.cs",
    "content": "﻿/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Definitions internal to Minikin\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Definitions internal to Minikin\n\n\n\n\n\nnamespace minikin\n{\n\n// An RAII wrapper for hb_blob_t\npublic class HbBlob : System.IDisposable\n{\n  // Takes ownership of hb_blob_t object, caller is no longer\n  // responsible for calling hb_blob_destroy().\n  public HbBlob(hb_blob_t blob)\n  {\n\t  this.mBlob = blob;\n  }\n\n  public void Dispose()\n  {\n\t  hb_blob_destroy(mBlob);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: const byte* get() const\n  public byte get()\n  {\n//C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types:\n//ORIGINAL LINE: const char* data = hb_blob_get_data(mBlob, null);\n\tchar data = hb_blob_get_data(mBlob, null);\n//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\treturn reinterpret_cast<const byte>(data);\n  }\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int size() const\n  public int size()\n  {\n\t  return (int)hb_blob_get_length(mBlob);\n  }\n\n  private hb_blob_t mBlob;\n}\n\n} // namespace minikin\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/SparseBitSet.cs",
    "content": "﻿/*\n * Copyright (C) 2012 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\nnamespace minikin\n{\n\n\n\n#if _WIN32\n#else\n#endif\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint SparseBitSet::nextSetBit(uint fromIndex) const\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/SparseBitSet.h.cs",
    "content": "﻿/*\n * Copyright (C) 2012 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n// ---------------------------------------------------------------------------\n\nnamespace minikin\n{\n\n// This is an implementation of a set of integers. It is optimized for\n// values that are somewhat sparse, in the ballpark of a maximum value\n// of thousands to millions. It is particularly efficient when there are\n// large gaps. The motivating example is Unicode coverage of a font, but\n// the abstraction itself is fully general.\npublic class SparseBitSet\n{\n\tprivate bool InstanceFieldsInitialized = false;\n\n\tprivate void InitializeInstanceFields()\n\t{\n\t\tkElMask = (1 << kLogBitsPerEl) - 1;\n\t\tkElFirst = ((uint)1) << kElMask;\n\t}\n\n  // Create an empty bit set.\n  public SparseBitSet()\n  {\n\t  if (!InstanceFieldsInitialized)\n\t  {\n\t\t  InitializeInstanceFields();\n\t\t  InstanceFieldsInitialized = true;\n\t  }\n\t  this.mMaxVal = 0;\n  }\n\n  // Initialize the set to a new value, represented by ranges. For\n  // simplicity, these ranges are arranged as pairs of values,\n  // inclusive of start, exclusive of end, laid out in a uint32 array.\n  public SparseBitSet(uint ranges, int nRanges) : this()\n  {\n\t  if (!InstanceFieldsInitialized)\n\t  {\n\t\t  InitializeInstanceFields();\n\t\t  InstanceFieldsInitialized = true;\n\t  }\n\tinitFromRanges(ranges, nRanges);\n  }\n\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//  SparseBitSet(SparseBitSet&&) = default;\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//  SparseBitSet& operator =(SparseBitSet&&) = default;\n\n  // Determine whether the value is included in the set\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: bool get(uint ch) const\n  public bool get(uint ch)\n  {\n\tif (ch >= mMaxVal)\n\t{\n\t  return false;\n\t}\n\tuint[] bitmap = mBitmaps[mIndices[ch >> kLogValuesPerPage]];\n\tuint index = ch & kPageMask;\n\treturn (bitmap[index >> kLogBitsPerEl] & (kElFirst >> (index & kElMask))) != 0;\n  }\n\n  // One more than the maximum value in the set, or zero if empty\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint length() const\n  public uint length()\n  {\n\t  return mMaxVal;\n  }\n\n  // The next set bit starting at fromIndex, inclusive, or kNotFound\n  // if none exists.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint nextSetBit(uint fromIndex) const;\n\tpublic uint nextSetBit(uint fromIndex)\n\t{\n\t  if (fromIndex >= mMaxVal)\n\t  {\n\t\treturn GlobalMembers.kNotFound;\n\t  }\n\t  uint fromPage = fromIndex >> kLogValuesPerPage;\n\t  element[] bitmap = &mBitmaps[mIndices[fromPage]];\n\t  uint offset = (fromIndex & kPageMask) >> kLogBitsPerEl;\n\t  element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));\n\t  if (e != 0)\n\t  {\n\t\treturn (fromIndex & ~kElMask) + CountLeadingZeros(e);\n\t  }\n\t  for (uint j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++)\n\t  {\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: e = bitmap[j];\n\t\te.CopyFrom(bitmap[j]);\n\t\tif (e != 0)\n\t\t{\n\t\t  return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);\n\t\t}\n\t  }\n\t  uint maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;\n\t  for (uint page = fromPage + 1; page < maxPage; page++)\n\t  {\n\t\tUInt16 index = mIndices[page];\n\t\tif (index == mZeroPageIndex)\n\t\t{\n\t\t  continue;\n\t\t}\n\t\tbitmap = &mBitmaps[index];\n\t\tfor (uint j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++)\n\t\t{\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: e = bitmap[j];\n\t\t  e.CopyFrom(bitmap[j]);\n\t\t  if (e != 0)\n\t\t  {\n\t\t\treturn (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);\n\t\t  }\n\t\t}\n\t  }\n\t  return GlobalMembers.kNotFound;\n\t}\n\n  public uint kNotFound = ~0u;\n\n\tpublic void initFromRanges(uint[] ranges, int nRanges)\n\t{\n\t  if (nRanges == 0)\n\t  {\n\t\treturn;\n\t  }\n\t  uint maxVal = ranges[nRanges * 2 - 1];\n\t  if (maxVal >= kMaximumCapacity)\n\t  {\n\t\treturn;\n\t  }\n\t  mMaxVal = maxVal;\n\t  mIndices.reset(Arrays.InitializeWithDefaultInstances<UInt16>((mMaxVal + kPageMask) >> kLogValuesPerPage));\n\t  uint nPages = calcNumPages(ranges, nRanges);\n\t  mBitmaps.reset(Arrays.InitializeWithDefaultInstances<element>(nPages << (kLogValuesPerPage - kLogBitsPerEl)));\n\t  mZeroPageIndex = noZeroPage;\n\t  uint nonzeroPageEnd = 0;\n\t  uint currentPage = 0;\n\t  for (int i = 0; i < nRanges; i++)\n\t  {\n\t\tuint start = ranges[i * 2];\n\t\tuint end = ranges[i * 2 + 1];\n\t\tLOG_ALWAYS_FATAL_IF(end < start); // make sure range size is nonnegative\n\t\tuint startPage = start >> kLogValuesPerPage;\n\t\tuint endPage = (end - 1) >> kLogValuesPerPage;\n\t\tif (startPage >= nonzeroPageEnd)\n\t\t{\n\t\t  if (startPage > nonzeroPageEnd)\n\t\t  {\n\t\t\tif (mZeroPageIndex == noZeroPage)\n\t\t\t{\n\t\t\t  mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);\n\t\t\t}\n\t\t\tfor (uint j = nonzeroPageEnd; j < startPage; j++)\n\t\t\t{\n\t\t\t  mIndices[j] = mZeroPageIndex;\n\t\t\t}\n\t\t  }\n\t\t  mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);\n\t\t}\n    \n\t\tint index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) + ((start & kPageMask) >> kLogBitsPerEl);\n\t\tint nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;\n\t\tif (nElements == 1)\n\t\t{\n\t\t  mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) & (kElAllOnes << ((~end + 1) & kElMask));\n\t\t}\n\t\telse\n\t\t{\n\t\t  mBitmaps[index] |= kElAllOnes >> (start & kElMask);\n\t\t  for (int j = 1; j < nElements - 1; j++)\n\t\t  {\n\t\t\tmBitmaps[index + j] = kElAllOnes;\n\t\t  }\n\t\t  mBitmaps[index + nElements - 1] |= kElAllOnes << ((~end + 1) & kElMask);\n\t\t}\n\t\tfor (int j = startPage + 1; j < endPage + 1; j++)\n\t\t{\n\t\t  mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);\n\t\t}\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: nonzeroPageEnd = endPage + 1;\n\t\tnonzeroPageEnd.CopyFrom(endPage + 1);\n\t  }\n\t}\n\n  private const uint kMaximumCapacity = 0xFFFFFF;\n  private const int kLogValuesPerPage = 8;\n  private int kPageMask = (1 << kLogValuesPerPage) - 1;\n  private const int kLogBytesPerEl = 2;\n  private int kLogBitsPerEl = kLogBytesPerEl + 3;\n  private int kElMask;\n  // invariant: sizeof(element) == (1 << kLogBytesPerEl)\n  private uint kElAllOnes = ~((uint)0);\n  private uint kElFirst;\n  private const UInt16 noZeroPage = 0xFFFF;\n\n\tpublic uint calcNumPages(uint[] ranges, int nRanges)\n\t{\n\t  bool haveZeroPage = false;\n\t  uint nonzeroPageEnd = 0;\n\t  uint nPages = 0;\n\t  for (int i = 0; i < nRanges; i++)\n\t  {\n\t\tuint start = ranges[i * 2];\n\t\tuint end = ranges[i * 2 + 1];\n\t\tuint startPage = start >> kLogValuesPerPage;\n\t\tuint endPage = (end - 1) >> kLogValuesPerPage;\n\t\tif (startPage >= nonzeroPageEnd)\n\t\t{\n\t\t  if (startPage > nonzeroPageEnd)\n\t\t  {\n\t\t\tif (!haveZeroPage)\n\t\t\t{\n\t\t\t  haveZeroPage = true;\n\t\t\t  nPages++;\n\t\t\t}\n\t\t  }\n\t\t  nPages++;\n\t\t}\n\t\tnPages += endPage - startPage;\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: nonzeroPageEnd = endPage + 1;\n\t\tnonzeroPageEnd.CopyFrom(endPage + 1);\n\t  }\n\t  return nPages;\n\t}\n\tpublic int CountLeadingZeros(element x)\n\t{\n\t  return sizeof(element) <= sizeof(int) ? clz_win(x) : clzl_win(x);\n\t}\n\n  private uint mMaxVal = new uint();\n\n  private std::unique_ptr<UInt16[]> mIndices = new std::unique_ptr<UInt16[]>();\n  private std::unique_ptr<uint[]> mBitmaps = new std::unique_ptr<uint[]>();\n  private UInt16 mZeroPageIndex = new UInt16();\n\n  // Forbid copy and assign.\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  SparseBitSet(const SparseBitSet&) = delete;\n//C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n//  void operator =(const SparseBitSet&) = delete;\n}\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/StringFunctions.cs",
    "content": "﻿//----------------------------------------------------------------------------------------\n//\tCopyright © 2006 - 2018 Tangible Software Solutions, Inc.\n//\tThis class can be used by anyone provided that the copyright notice remains intact.\n//\n//\tThis class provides the ability to replicate various classic C string functions\n//\twhich don't have exact equivalents in the .NET Framework.\n//----------------------------------------------------------------------------------------\ninternal static class StringFunctions\n{\n\t//------------------------------------------------------------------------------------\n\t//\tThis method allows replacing a single character in a string, to help convert\n\t//\tC++ code where a single character in a character array is replaced.\n\t//------------------------------------------------------------------------------------\n\tpublic static string ChangeCharacter(string sourceString, int charIndex, char newChar)\n\t{\n\t\treturn (charIndex > 0 ? sourceString.Substring(0, charIndex) : \"\")\n\t\t\t+ newChar.ToString() + (charIndex < sourceString.Length - 1 ? sourceString.Substring(charIndex + 1) : \"\");\n\t}\n\n\t//------------------------------------------------------------------------------------\n\t//\tThis method replicates the classic C string function 'isxdigit' (and 'iswxdigit').\n\t//------------------------------------------------------------------------------------\n\tpublic static bool IsXDigit(char character)\n\t{\n\t\tif (char.IsDigit(character))\n\t\t\treturn true;\n\t\telse if (\"ABCDEFabcdef\".IndexOf(character) > -1)\n\t\t\treturn true;\n\t\telse\n\t\t\treturn false;\n\t}\n\n\t//------------------------------------------------------------------------------------\n\t//\tThis method replicates the classic C string function 'strchr' (and 'wcschr').\n\t//------------------------------------------------------------------------------------\n\tpublic static string StrChr(string stringToSearch, char charToFind)\n\t{\n\t\tint index = stringToSearch.IndexOf(charToFind);\n\t\tif (index > -1)\n\t\t\treturn stringToSearch.Substring(index);\n\t\telse\n\t\t\treturn null;\n\t}\n\n\t//------------------------------------------------------------------------------------\n\t//\tThis method replicates the classic C string function 'strrchr' (and 'wcsrchr').\n\t//------------------------------------------------------------------------------------\n\tpublic static string StrRChr(string stringToSearch, char charToFind)\n\t{\n\t\tint index = stringToSearch.LastIndexOf(charToFind);\n\t\tif (index > -1)\n\t\t\treturn stringToSearch.Substring(index);\n\t\telse\n\t\t\treturn null;\n\t}\n\n\t//------------------------------------------------------------------------------------\n\t//\tThis method replicates the classic C string function 'strstr' (and 'wcsstr').\n\t//------------------------------------------------------------------------------------\n\tpublic static string StrStr(string stringToSearch, string stringToFind)\n\t{\n\t\tint index = stringToSearch.IndexOf(stringToFind);\n\t\tif (index > -1)\n\t\t\treturn stringToSearch.Substring(index);\n\t\telse\n\t\t\treturn null;\n\t}\n\n\t//------------------------------------------------------------------------------------\n\t//\tThis method replicates the classic C string function 'strtok' (and 'wcstok').\n\t//\tNote that the .NET string 'Split' method cannot be used to replicate 'strtok' since\n\t//\tit doesn't allow changing the delimiters between each token retrieval.\n\t//------------------------------------------------------------------------------------\n\tprivate static string activeString;\n\tprivate static int activePosition;\n\tpublic static string StrTok(string stringToTokenize, string delimiters)\n\t{\n\t\tif (stringToTokenize != null)\n\t\t{\n\t\t\tactiveString = stringToTokenize;\n\t\t\tactivePosition = -1;\n\t\t}\n\n\t\t//the stringToTokenize was never set:\n\t\tif (activeString == null)\n\t\t\treturn null;\n\n\t\t//all tokens have already been extracted:\n\t\tif (activePosition == activeString.Length)\n\t\t\treturn null;\n\n\t\t//bypass delimiters:\n\t\tactivePosition++;\n\t\twhile (activePosition < activeString.Length && delimiters.IndexOf(activeString[activePosition]) > -1)\n\t\t{\n\t\t\tactivePosition++;\n\t\t}\n\n\t\t//only delimiters were left, so return null:\n\t\tif (activePosition == activeString.Length)\n\t\t\treturn null;\n\n\t\t//get starting position of string to return:\n\t\tint startingPosition = activePosition;\n\n\t\t//read until next delimiter:\n\t\tdo\n\t\t{\n\t\t\tactivePosition++;\n\t\t} while (activePosition < activeString.Length && delimiters.IndexOf(activeString[activePosition]) == -1);\n\n\t\treturn activeString.Substring(startingPosition, activePosition - startingPosition);\n\t}\n}"
  },
  {
    "path": "FlutterBinding/Minikin/WordBreaker.cs",
    "content": "﻿/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n\n\nnamespace minikin\n{\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint WordBreaker::current() const\n\n// Customized iteratorNext that takes care of both resets and our modifications\n// to ICU's behavior.\n\npublic enum ScanState\n{\n  START,\n  SAW_AT,\n  SAW_COLON,\n  SAW_COLON_SLASH,\n  SAW_COLON_SLASH_SLASH,\n}\n\n\n\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint WordBreaker::wordStart() const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: uint WordBreaker::wordEnd() const\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int WordBreaker::breakBadness() const\n\n\n} // namespace minikin\n"
  },
  {
    "path": "FlutterBinding/Minikin/WordBreaker.h.cs",
    "content": "﻿using System;\n\n/*\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A wrapper around ICU's line break iterator, that gives customized line\n * break opportunities, as well as identifying words for the purpose of\n * hyphenation.\n */\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/brkiter.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n\nnamespace minikin\n{\n\npublic class WordBreaker : System.IDisposable\n{\n  public void Dispose()\n  {\n\t  finish();\n  }\n\n\tpublic void setLocale(icu.Locale locale)\n\t{\n\t  UErrorCode status = U_ZERO_ERROR;\n\t  mBreakIterator.reset(icu.BreakIterator.createLineInstance(locale, status));\n\t  // TODO: handle failure status\n\t  if (mText != null)\n\t  {\n\t\tmBreakIterator.setText(mUText, status);\n\t  }\n\t  mIteratorWasReset = true;\n\t}\n\n\tpublic void setText(UInt16 data, int size)\n\t{\n\t  mText = data;\n\t  mTextSize = size;\n\t  mIteratorWasReset = false;\n\t  mLast = 0;\n\t  mCurrent = 0;\n\t  mScanOffset = 0;\n\t  mInEmailOrUrl = false;\n\t  UErrorCode status = U_ZERO_ERROR;\n\t//C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n\t  utext_openUChars(mUText, reinterpret_cast<const UChar>(data), size, status);\n\t  mBreakIterator.setText(mUText, status);\n\t  mBreakIterator.first();\n\t}\n\n  // Advance iterator to next word break. Return offset, or -1 if EOT\n\tpublic uint next()\n\t{\n\t  mLast = mCurrent;\n    \n\t  detectEmailOrUrl();\n\t  if (mInEmailOrUrl)\n\t  {\n\t\tmCurrent = findNextBreakInEmailOrUrl();\n\t  }\n\t  else\n\t  { // Business as usual\n\t\tmCurrent = (uint)iteratorNext();\n\t  }\n\t  return mCurrent;\n\t}\n\n  // Current offset of iterator, equal to 0 at BOT or last return from next()\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: System.IntPtr current() const;\n\tpublic uint current()\n\t{\n\t  return mCurrent;\n\t}\n\n  // After calling next(), wordStart() and wordEnd() are offsets defining the\n  // previous word. If wordEnd <= wordStart, it's not a word for the purpose of\n  // hyphenation.\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: System.IntPtr wordStart() const;\n\tpublic uint wordStart()\n\t{\n\t  if (mInEmailOrUrl)\n\t  {\n\t\treturn mLast;\n\t  }\n\t  uint result = mLast;\n\t  while (result < mCurrent)\n\t  {\n\t\tUChar32 c = new UChar32();\n\t\tuint ix = result;\n\t\tU16_NEXT(mText, ix, mCurrent, c);\n\t\tint lb = u_getIntPropertyValue(c, UCHAR_LINE_BREAK);\n\t\t// strip leading punctuation, defined as OP and QU line breaking classes,\n\t\t// see UAX #14\n\t\tif (!(lb == U_LB_OPEN_PUNCTUATION || lb == U_LB_QUOTATION))\n\t\t{\n\t\t  break;\n\t\t}\n\t\tresult = ix;\n\t  }\n\t  return result;\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: System.IntPtr wordEnd() const;\n\tpublic uint wordEnd()\n\t{\n\t  if (mInEmailOrUrl)\n\t  {\n\t\treturn mLast;\n\t  }\n\t  uint result = mCurrent;\n\t  while (result > mLast)\n\t  {\n\t\tUChar32 c = new UChar32();\n\t\tuint ix = result;\n\t\tU16_PREV(mText, mLast, ix, c);\n\t\tint gc_mask = U_GET_GC_MASK(c);\n\t\t// strip trailing space and punctuation\n\t\tif ((gc_mask & (U_GC_ZS_MASK | U_GC_P_MASK)) == 0)\n\t\t{\n\t\t  break;\n\t\t}\n\t\tresult = ix;\n\t  }\n\t  return result;\n\t}\n\n//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//ORIGINAL LINE: int breakBadness() const;\n\tpublic int breakBadness()\n\t{\n\t  return (mInEmailOrUrl && mCurrent < mScanOffset) ? 1 : 0;\n\t}\n\n\tpublic void finish()\n\t{\n\t  mText = null;\n\t  // Note: calling utext_close multiply is safe\n\t  utext_close(mUText);\n\t}\n\n\tpublic int iteratorNext()\n\t{\n\t  int result = new int();\n\t  do\n\t  {\n\t\tif (mIteratorWasReset)\n\t\t{\n\t\t  result = mBreakIterator.following(mCurrent);\n\t\t  mIteratorWasReset = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t  result = mBreakIterator.next();\n\t\t}\n\t  } while (!(result == icu.BreakIterator.DONE || (int)result == mTextSize || isBreakValid(mText, mTextSize, result)));\n\t  return result;\n\t}\n\tpublic void detectEmailOrUrl()\n\t{\n\t  // scan forward from current ICU position for email address or URL\n\t  if (mLast >= mScanOffset)\n\t  {\n\t\tScanState state = ScanState.START;\n\t\tint i = new int();\n\t\tfor (i = mLast; i < mTextSize; i++)\n\t\t{\n\t\t  UInt16 c = mText[i];\n\t\t  // scan only ASCII characters, stop at space\n\t\t  if (!(' ' < c && c <= 0x007E))\n\t\t  {\n\t\t\tbreak;\n\t\t  }\n\t\t  if (state == ScanState.START && c == '@')\n\t\t  {\n\t\t\tstate = ScanState.SAW_AT;\n\t\t  }\n\t\t  else if (state == ScanState.START && c == ':')\n\t\t  {\n\t\t\tstate = ScanState.SAW_COLON;\n\t\t  }\n\t\t  else if (state == ScanState.SAW_COLON || state == ScanState.SAW_COLON_SLASH)\n\t\t  {\n\t\t\tif (c == '/')\n\t\t\t{\n\t\t\t  state = (ScanState)((int)state + 1); // next state adds a slash\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t  state = ScanState.START;\n\t\t\t}\n\t\t  }\n\t\t}\n\t\tif (state == ScanState.SAW_AT || state == ScanState.SAW_COLON_SLASH_SLASH)\n\t\t{\n\t\t  if (!mBreakIterator.isBoundary(i))\n\t\t  {\n\t\t\t// If there are combining marks or such at the end of the URL or the\n\t\t\t// email address, consider them a part of the URL or the email, and skip\n\t\t\t// to the next actual boundary.\n\t\t\ti = mBreakIterator.following(i);\n\t\t  }\n\t\t  mInEmailOrUrl = true;\n\t\t  mIteratorWasReset = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t  mInEmailOrUrl = false;\n\t\t}\n\t\tmScanOffset = i;\n\t  }\n\t}\n\tpublic uint findNextBreakInEmailOrUrl()\n\t{\n            // special rules for email addresses and URL's as per Chicago Manual of Style\n            // (16th ed.)\n\n            UInt16 lastChar = mText[mLast];\n\t  uint i;\n\t  for (i = mLast + 1; i < mScanOffset; i++)\n\t  {\n\t\tif (breakAfter(new UInt16(lastChar)))\n\t\t{\n\t\t  break;\n\t\t}\n\t\t// break after double slash\n\t\tif (lastChar == '/' && i >= mLast + 2 && mText[i - 2] == '/')\n\t\t{\n\t\t  break;\n\t\t}\n\t\tUInt16 thisChar = mText[i];\n\t\t// never break after hyphen\n\t\tif (lastChar != '-')\n\t\t{\n\t\t  if (breakBefore(new UInt16(thisChar)))\n\t\t  {\n\t\t\tbreak;\n\t\t  }\n\t\t  // break before single slash\n\t\t  if (thisChar == '/' && lastChar != '/' && !(i + 1 < mScanOffset && mText[i + 1] == '/'))\n\t\t  {\n\t\t\tbreak;\n\t\t  }\n\t\t}\n\t//C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n\t//ORIGINAL LINE: lastChar = thisChar;\n\t\tlastChar.CopyFrom(thisChar);\n\t  }\n\t  return i;\n\t}\n\n  private std::unique_ptr<icu.BreakIterator> mBreakIterator = new std::unique_ptr<icu.BreakIterator>();\n  private UText mUText = UTEXT_INITIALIZER;\n  private UInt16[] mText = null;\n  private int mTextSize = new int();\n  private IntPtr mLast;\n  private IntPtr mCurrent;\n  private bool mIteratorWasReset;\n\n  // state for the email address / url detector\n  private IntPtr mScanOffset;\n  private bool mInEmailOrUrl;\n}\n\n} // namespace minikin\n\n"
  },
  {
    "path": "FlutterBinding/Minikin/minikin.Hyphenator.cs",
    "content": "﻿namespace minikin\n{\n\n\tpublic class Hyphenator\n\t{\n//C++ TO C# CONVERTER WARNING: The original C++ declaration of the following method implementation was not found:\n\t\tpublic void hyphenate(vector<HyphenationType> result, UInt16 word, int len, icu.Locale locale)\n\t\t{\n\t\t  result.clear();\n\t\t  result.resize(len);\n\t\t  int paddedLen = len + 2; // start and stop code each count for 1\n\t\t  if (patternData != null && len >= minPrefix + minSuffix && paddedLen <= MAX_HYPHENATED_SIZE)\n\t\t  {\n\t\t\tUInt16[] alpha_codes = Arrays.InitializeWithDefaultInstances<UInt16>(MAX_HYPHENATED_SIZE);\n\t\t\tHyphenationType hyphenValue = alphabetLookup(alpha_codes, word, len);\n\t\t\tif (hyphenValue != HyphenationType.DONT_BREAK)\n\t\t\t{\n\t\t\t  hyphenateFromCodes(result.data(), alpha_codes, paddedLen, hyphenValue);\n\t\t\t  return;\n\t\t\t}\n\t\t\t// TODO: try NFC normalization\n\t\t\t// TODO: handle non-BMP Unicode (requires remapping of offsets)\n\t\t  }\n\t\t  // Note that we will always get here if the word contains a hyphen or a soft\n\t\t  // hyphen, because the alphabet is not expected to contain a hyphen or a soft\n\t\t  // hyphen character, so alphabetLookup would return DONT_BREAK.\n\t\t  hyphenateWithNoPatterns(result.data(), word, len, locale);\n\t\t}\n\t}\n}"
  },
  {
    "path": "FlutterBinding/Minikin/minikin.SparseBitSet.cs",
    "content": "﻿namespace minikin\n{\n\n\tpublic class SparseBitSet\n\t{\n//C++ TO C# CONVERTER WARNING: The original C++ declaration of the following method implementation was not found:\n\t\tpublic int CountLeadingZeros(element x)\n\t\t{\n\t\t  // Note: GCC / clang builtin\n\t\t  return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);\n\t\t}\n\t}\n}"
  },
  {
    "path": "FlutterBinding/Minikin/minikin.android.cs",
    "content": "﻿namespace minikin\n{\n\n\tpublic class android\n\t{\n//C++ TO C# CONVERTER WARNING: The original C++ declaration of the following method implementation was not found:\n\t\tpublic android.hash_t FontStyle.hash()\n\t\t{\n\t\t  uint hash = android.JenkinsHashMix(0, bits);\n\t\t  hash = android.JenkinsHashMix(hash, mLanguageListId);\n\t\t  return android.JenkinsHashWhiten(hash);\n\t\t}\n\t}\n}"
  },
  {
    "path": "FlutterBinding/Txt/DefineConstants.cs",
    "content": "﻿//internal static class DefineConstants\n//{\n//\tpublic const int SK_CPU_X86 = 1;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSE1 = 10;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSE2 = 20;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSE3 = 30;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSSE3 = 31;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSE41 = 41;\n//\tpublic const int SK_CPU_SSE_LEVEL_SSE42 = 42;\n//\tpublic const int SK_CPU_SSE_LEVEL_AVX = 51;\n//\tpublic const int SK_CPU_SSE_LEVEL_AVX2 = 52;\n//\tpublic const int SK_CPU_SSE_LEVEL_AVX512 = 60;\n//\tpublic const int SK_CPU_SSE_LEVEL = 0;\n//\tpublic const int SKIA_IMPLEMENTATION = 0;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const int SK_R32_SHIFT = 16;\n//\tpublic const int SK_R32_SHIFT = 24;\n//\tpublic const int SK_R32_SHIFT = 0;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const int SK_G32_SHIFT = 8;\n//\tpublic const int SK_G32_SHIFT = 16;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const int SK_B32_SHIFT = 0;\n//\tpublic const int SK_B32_SHIFT = 8;\n//\tpublic const int SK_B32_SHIFT = 16;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const int SK_A32_SHIFT = 24;\n//\tpublic const int SK_A32_SHIFT = 0;\n//\tpublic const int SK_SUPPORT_GPU = 1;\n//\tpublic const int SK_SUPPORT_ATLAS_TEXT = 0;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const string SK_SIZE_T_SPECIFIER = \"%Iu\";\n//\tpublic const string SK_SIZE_T_SPECIFIER = \"%zu\";\n//\tpublic const int SK_ALLOW_STATIC_GLOBAL_INITIALIZERS = 1;\n//\tpublic const int GR_TEST_UTILS = 0;\n////C++ TO C# CONVERTER TODO TASK: The following #define constant was defined in different ways:\n//\tpublic const int SK_HISTOGRAMS_ENABLED = 1;\n//\tpublic const int SK_HISTOGRAMS_ENABLED = 0;\n//\tpublic const int SKIA_VERSION_MAJOR = 1;\n//\tpublic const int SKIA_VERSION_MINOR = 0;\n//\tpublic const int SKIA_VERSION_PATCH = 0;\n//\tpublic const int SK_MaxS32FitsInFloat = 2147483520;\n//\tpublic const int SK_FLT_DECIMAL_DIG = 9;\n//\tpublic const int SK_SCALAR_IS_FLOAT = 1;\n//\tpublic const float SK_Scalar1 = 1.0f;\n//\tpublic const float SK_ScalarHalf = 0.5f;\n//\tpublic const float SK_ScalarSqrt2 = 1.41421356f;\n//\tpublic const float SK_ScalarPI = 3.14159265f;\n//\tpublic const float SK_ScalarTanPIOver8 = 0.414213562f;\n//\tpublic const float SK_ScalarRoot2Over2 = 0.707106781f;\n//\tpublic const int SK_GLIBCXX_4_7_0 = 20120322;\n//\tpublic const int SK_GLIBCXX_4_5_4 = 20120702;\n//\tpublic const int SK_GLIBCXX_4_6_4 = 20121127;\n//\tpublic const int SkStrAppendU32_MaxSize = 10;\n//\tpublic const int SkStrAppendU64_MaxSize = 20;\n//\tpublic const int SkStrAppendScalar_MaxSize = 15;\n//\tpublic const int U_USING_ICU_NAMESPACE = 0;\n//}"
  },
  {
    "path": "FlutterBinding/Txt/GlobalMembers.cs",
    "content": "﻿//using System.Collections.Generic;\n\n//namespace FlutterBinding.Txt\n//{\n//\tpublic static class GlobalMembers\n//\t{\n//\tpublic static readonly minikin.FontFamily g_null_family;\n\n//\tpublic static hb_blob_t GetTable(HarfBuzzSharp.Face face, hb_tag_t tag, object context)\n//\t{\n////C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n//\t  SkTypeface typeface = reinterpret_cast<SkTypeface>(context);\n\n//\t  int table_size = typeface.getTableSize(tag);\n//\t  if (table_size == 0)\n//\t  {\n//\t\treturn null;\n//\t  }\n////C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#:\n//\t  object buffer = malloc(table_size);\n//\t  if (buffer == null)\n//\t  {\n//\t\treturn null;\n//\t  }\n\n//\t  int actual_size = typeface.getTableData(tag, 0, table_size, buffer);\n//\t  if (table_size != actual_size)\n//\t  {\n////C++ TO C# CONVERTER TODO TASK: The memory management function 'free' has no equivalent in C#:\n//\t\tfree(buffer);\n//\t\treturn null;\n//\t  }\n////C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n//\t  return hb_blob_create(reinterpret_cast<char>(buffer), table_size, HB_MEMORY_MODE_WRITABLE, buffer, free);\n//\t}\n\n\n////C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//\t//FontSkia::~FontSkia() = default;\n\n//\tinternal static void FontSkia_SetSkiaPaint(SKTypeface typeface, SKPaint skPaint, minikin.MinikinPaint paint)\n//\t{\n//\t  skPaint.setTypeface(typeface);\n//\t  skPaint.setTextEncoding(SKPaint.kGlyphID_TextEncoding);\n//\t  // TODO: set more paint parameters from Minikin\n//\t  skPaint.setTextSize(paint.size);\n//\t}\n\n//\tpublic static GlyphTypeface GetGlyphTypeface(minikin.Layout layout, int index)\n//\t{\n//\t  FontSkia font = (FontSkia)layout.getFont(index);\n//\t  return new GlyphTypeface(font.GetSkTypeface(), layout.getFakery(index));\n//\t}\n\n//\t// Return ranges of text that have the same typeface in the layout.\n//\tpublic static List<Paragraph.Range<int>> GetLayoutTypefaceRuns(minikin.Layout layout)\n//\t{\n//\t  List<Paragraph.Range<int>> result = new List<Paragraph.Range<int>>();\n//\t  if (layout.nGlyphs() == 0)\n//\t  {\n//\t\treturn result;\n//\t  }\n//\t  int run_start = 0;\n//\t  GlyphTypeface run_typeface = GlobalMembers.GetGlyphTypeface(layout, run_start);\n//\t  for (int i = 1; i < layout.nGlyphs(); ++i)\n//\t  {\n//\t\tGlyphTypeface typeface = GlobalMembers.GetGlyphTypeface(layout, i);\n//\t\tif (typeface != run_typeface)\n//\t\t{\n//\t\t  result.Add(run_start, i);\n////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n////ORIGINAL LINE: run_start = i;\n//\t\t  run_start.CopyFrom(i);\n////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n////ORIGINAL LINE: run_typeface = typeface;\n//\t\t  run_typeface.CopyFrom(typeface);\n//\t\t}\n//\t  }\n//\t  result.Add(run_start, layout.nGlyphs());\n//\t  return result;\n//\t}\n\n//\tpublic static int GetWeight(FontWeight weight)\n//\t{\n//\t  switch (weight)\n//\t  {\n//\t\tcase FontWeight.w100:\n//\t\t  return 1;\n//\t\tcase FontWeight.w200:\n//\t\t  return 2;\n//\t\tcase FontWeight.w300:\n//\t\t  return 3;\n//\t\tcase FontWeight.w400: // Normal.\n//\t\t  return 4;\n//\t\tcase FontWeight.w500:\n//\t\t  return 5;\n//\t\tcase FontWeight.w600:\n//\t\t  return 6;\n//\t\tcase FontWeight.w700: // Bold.\n//\t\t  return 7;\n//\t\tcase FontWeight.w800:\n//\t\t  return 8;\n//\t\tcase FontWeight.w900:\n//\t\t  return 9;\n//\t\tdefault:\n//\t\t  return -1;\n//\t  }\n//\t}\n\n//\tpublic static int GetWeight(TextStyle style)\n//\t{\n//\t  return GlobalMembers.GetWeight(style.font_weight);\n//\t}\n\n//\tpublic static bool GetItalic(TextStyle style)\n//\t{\n//\t  switch (style.font_style)\n//\t  {\n//\t\tcase FontStyle.italic:\n//\t\t  return true;\n//\t\tcase FontStyle.normal:\n//\t\tdefault:\n//\t\t  return false;\n//\t  }\n//\t}\n\n//\tpublic static minikin.FontStyle GetMinikinFontStyle(TextStyle style)\n//\t{\n//\t  uint language_list_id = string.IsNullOrEmpty(style.locale) ? minikin.FontLanguageListCache.kEmptyListId : minikin.FontStyle.registerLanguageList(style.locale);\n////C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n////ORIGINAL LINE: return minikin::FontStyle(language_list_id, 0, GetWeight(style), GetItalic(style));\n//\t  return new minikin.FontStyle(new uint(language_list_id), 0, GlobalMembers.GetWeight(new TextStyle(style)), GlobalMembers.GetItalic(style));\n//\t}\n\n//\tpublic static void GetFontAndMinikinPaint(TextStyle style, minikin.FontStyle font, minikin.MinikinPaint paint)\n//\t{\n////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n////ORIGINAL LINE: *font = GetMinikinFontStyle(style);\n//\t  font.CopyFrom(GlobalMembers.GetMinikinFontStyle(style));\n//\t  paint.size = style.font_size;\n//\t  // Divide by font size so letter spacing is pixels, not proportional to font\n//\t  // size.\n//\t  paint.letterSpacing = style.letter_spacing / style.font_size;\n//\t  paint.wordSpacing = style.word_spacing;\n//\t  paint.scaleX = 1.0f;\n//\t  // Prevent spacing rounding in Minikin. This causes jitter when switching\n//\t  // between same text content with different runs composing it, however, it\n//\t  // also produces more accurate layouts.\n//\t  paint.paintFlags |= minikin.MinikinPaintFlags.LinearTextFlag;\n//\t}\n\n//\tpublic static void FindWords(List<UInt16> text, int start, int end, List<Paragraph.Range<int>> words)\n//\t{\n//\t  bool in_word = false;\n//\t  int word_start = new int();\n//\t  for (int i = start; i < end; ++i)\n//\t  {\n//\t\tbool is_space = minikin.isWordSpace(text[i]);\n//\t\tif (!in_word && !is_space)\n//\t\t{\n////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n////ORIGINAL LINE: word_start = i;\n//\t\t  word_start.CopyFrom(i);\n//\t\t  in_word = true;\n//\t\t}\n//\t\telse if (in_word && is_space)\n//\t\t{\n//\t\t  words.Add(word_start, i);\n//\t\t  in_word = false;\n//\t\t}\n//\t  }\n//\t  if (in_word)\n//\t  {\n//\t\twords.Add(word_start, end);\n//\t  }\n//\t}\n\n\n//\tinternal const float kDoubleDecorationSpacing = 3.0f;\n\n////C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//\t//Paragraph::~Paragraph() = default;\n\n//\tpublic static string GetDefaultFontFamily()\n//\t{\n//\t  return \"Arial\";\n//\t}\n\n//\tpublic static string GetDefaultFontFamily()\n//\t{\n//\t  return \"sans-serif\";\n//\t}\n//\t}\n//}"
  },
  {
    "path": "FlutterBinding/Txt/SkTextBlob.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FlutterBinding.Txt\n{\n    public class SkTextBlob\n    {\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/Txt/asset_font_manager.cs",
    "content": "﻿//using SkiaSharp;\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"flutter/fml/macros.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkFontMgr.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkStream.h\"\n\n//namespace FlutterBinding.Txt\n//{\n\n//    public class AssetFontManager : SkiaSharp.SKFontManager, System.IDisposable\n//    {\n//        public AssetFontManager(FontAssetProvider font_provider)\n//        {\n//            this.font_provider_ = font_provider;\n//            //FML_DCHECK(font_provider_ != null);\n//        }\n\n//        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n//        //  public void Dispose();\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SkFontStyleSet* onMatchFamily(const char family_name_string[]) const override\n//        protected override SKFontStyleSet onMatchFamily(string family_name_string)\n//        {\n//            string family_name = family_name_string;\n//            return font_provider_.MatchFamily(family_name);\n//        }\n\n//        protected std::unique_ptr<FontAssetProvider> font_provider_ = new std::unique_ptr<FontAssetProvider>();\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: int onCountFamilies() const override\n//        private override int onCountFamilies()\n//        {\n//            return font_provider_.GetFamilyCount();\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: void onGetFamilyName(int index, SkString* familyName) const override\n//        private override void onGetFamilyName(int index, SkString familyName)\n//        {\n//            familyName.set(font_provider_.GetFamilyName(index).c_str());\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SkFontStyleSet* onCreateStyleSet(int index) const override\n//        private override SkFontStyleSet onCreateStyleSet(int index)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SkTypeface* onMatchFamilyStyle(const char familyName[], const SkFontStyle& style) const override\n//        private override SkTypeface onMatchFamilyStyle(string familyName, SkFontStyle style)\n//        {\n//            SkFontStyleSet font_style_set = font_provider_.MatchFamily((string)familyName);\n//            if (font_style_set == null)\n//            {\n//                return null;\n//            }\n//            return font_style_set.matchStyle(style);\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, const char* bcp47[], int bcp47Count, SkUnichar character) const override\n//        private override SkTypeface onMatchFamilyStyleCharacter(string familyName, SkFontStyle UnnamedParameter, string[] bcp47, int bcp47Count, SkUnichar character)\n//        {\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SkTypeface* onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const override\n//        private override SkTypeface onMatchFaceStyle(SkTypeface UnnamedParameter, SkFontStyle UnnamedParameter2)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SKTypeface onMakeFromData(sk_sp<SkData>, int ttcIndex) const override\n//        private override SKTypeface onMakeFromData(sk_sp<SkData> UnnamedParameter, int ttcIndex)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SKTypeface onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int ttcIndex) const override\n//        private override SKTypeface onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> UnnamedParameter, int ttcIndex)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SKTypeface onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override\n//        private override SKTypeface onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> UnnamedParameter, SkFontArguments UnnamedParameter2)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SKTypeface onMakeFromFile(const char path[], int ttcIndex) const override\n//        private override SKTypeface onMakeFromFile(string path, int ttcIndex)\n//        {\n//            FML_DCHECK(false);\n//            return null;\n//        }\n\n//        // |SkFontMgr|\n//        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n//        //ORIGINAL LINE: SKTypeface onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override\n//        private override SKTypeface onLegacyMakeTypeface(string familyName, SkFontStyle UnnamedParameter)\n//        {\n//            //FML_DCHECK(false);\n//            return null;\n//        }\n\n//        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n//        //FML_DISALLOW_COPY_AND_ASSIGN(AssetFontManager);\n//    }\n\n//    public class DynamicFontManager : AssetFontManager\n//    {\n//        public DynamicFontManager() : base(new TypefaceFontAssetProvider())\n//        {\n//        }\n\n//        public TypefaceFontAssetProvider font_provider()\n//        {\n//            return (TypefaceFontAssetProvider)(*font_provider_);\n//        }\n//    }\n\n//} // namespace FlutterBinding.Txt\n\n\n\n\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"flutter/fml/logging.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkString.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkTypeface.h\"\n\n//namespace FlutterBinding.Txt\n//{\n\n//    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n//    //AssetFontManager::~AssetFontManager() = default;\n\n//} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/font_asset_provider.cs",
    "content": "﻿///*\n// * Copyright 2018 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n\n///*\n// * Copyright 2018 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkFontMgr.h\"\n\n//namespace FlutterBinding.Txt\n//{\n\n//public abstract class FontAssetProvider : System.IDisposable\n//{\n////C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n////  virtual ~FontAssetProvider() = default;\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: virtual int GetFamilyCount() const = 0;\n//  public abstract int GetFamilyCount();\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: virtual string GetFamilyName(int index) const = 0;\n//  public abstract string GetFamilyName(int index);\n//  public abstract SkFontStyleSet MatchFamily(string family_name);\n\n\n//  // Return a canonicalized version of a family name that is suitable for\n//  // matching.\n//  protected static string CanonicalFamilyName(string family_name)\n//  {\n//\tstring result = new string(family_name.Length, 0);\n\n//\t// Convert ASCII characters to lower case.\n//\tstd::transform(family_name.GetEnumerator(), family_name.end(), result.GetEnumerator(), (char c) =>\n//\t{\n//\t\treturn (c & 0x80) ? c : global::tolower(c);\n//\t});\n\n//\treturn result;\n//  }\n//}\n\n//} // namespace FlutterBinding.Txt\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Txt/font_collection.cs",
    "content": "﻿//using System.Collections.Generic;\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"flutter/fml/macros.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/googletest/googletest/include/gtest/gtest_prod.h\" // nogncheck\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkFontMgr.h\"\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"third_party/skia/include/core/SkRefCnt.h\"\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_RESTRICT __restrict\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_RESTRICT __restrict__\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_API __declspec(dllexport)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_API __declspec(dllimport)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PREFETCH(ptr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGFAIL(message)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGCODE(...)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDEBUGF(...)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define __inline static __inline\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_log(x) logf(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_FloatNaN NAN\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n////C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n////ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n\nnamespace FlutterBinding.Txt\n{\n\n    public class FontCollection : System.IDisposable\n    {\n        public FontCollection()\n        {\n            this.enable_font_fallback_ = true;\n        }\n\n        ////C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        public void Dispose() { }\n\n        ////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        ////ORIGINAL LINE: int GetFontManagersCount() const\n        //  public int GetFontManagersCount()\n        //  {\n        //\treturn GetFontManagerOrder().Count;\n        //  }\n\n        //  public void SetDefaultFontManager(sk_sp<SkFontMgr> font_manager)\n        //  {\n        ////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n        ////ORIGINAL LINE: default_font_manager_ = font_manager;\n        //\tdefault_font_manager_.CopyFrom(font_manager);\n        //  }\n        //  public void SetAssetFontManager(sk_sp<SkFontMgr> font_manager)\n        //  {\n        ////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n        ////ORIGINAL LINE: asset_font_manager_ = font_manager;\n        //\tasset_font_manager_.CopyFrom(font_manager);\n        //  }\n        //  public void SetDynamicFontManager(sk_sp<SkFontMgr> font_manager)\n        //  {\n        ////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n        ////ORIGINAL LINE: dynamic_font_manager_ = font_manager;\n        //\tdynamic_font_manager_.CopyFrom(font_manager);\n        //  }\n        //  public void SetTestFontManager(sk_sp<SkFontMgr> font_manager)\n        //  {\n        ////C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n        ////ORIGINAL LINE: test_font_manager_ = font_manager;\n        //\ttest_font_manager_.CopyFrom(font_manager);\n        //  }\n\n        //  public minikin.FontCollection GetMinikinFontCollectionForFamily(string font_family, string locale)\n        //  {\n        //\t// Look inside the font collections cache first.\n        //\tFamilyKey family_key = new FamilyKey(font_family, locale);\n        //\tvar cached = font_collections_cache_.find(family_key);\n        ////C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n        //\tif (cached != font_collections_cache_.end())\n        //\t{\n        ////C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n        //\t  return cached.second;\n        //\t}\n\n        //\tforeach (sk_sp<SkFontMgr> manager in GetFontManagerOrder())\n        //\t{\n        //\t  minikin.FontFamily minikin_family = CreateMinikinFontFamily(manager, font_family);\n        //\t  if (minikin_family == null)\n        //\t  {\n        //\t\tcontinue;\n        //\t  }\n\n        //\t  // Create a vector of font families for the Minikin font collection.\n        //\t  List<minikin.FontFamily> minikin_families = new List<minikin.FontFamily>() {minikin_family};\n        //\t  if (enable_font_fallback_)\n        //\t  {\n        //\t\tforeach (string fallback_family in fallback_fonts_for_locale_[locale])\n        //\t\t{\n        //\t\t  minikin_families.Add(fallback_fonts_[fallback_family]);\n        //\t\t}\n        //\t  }\n\n        //\t  // Create the minikin font collection.\n        //\t  var font_collection = new minikin.FontCollection(minikin_families);\n        //\t  if (enable_font_fallback_)\n        //\t  {\n        //\t\tfont_collection.set_fallback_font_provider(std::make_unique<TxtFallbackFontProvider>(this));\n        //\t  }\n\n        //\t  // Cache the font collection for future queries.\n        //\t  font_collections_cache_[family_key] = font_collection;\n\n        //\t  return font_collection;\n        //\t}\n\n        //\tvar default_font_family = GetDefaultFontFamily();\n        //\tif (font_family != default_font_family)\n        //\t{\n        //\t  minikin.FontCollection default_collection = GetMinikinFontCollectionForFamily(default_font_family, \"\");\n        //\t  font_collections_cache_[family_key] = default_collection;\n        //\t  return default_collection;\n        //\t}\n\n        //\t// No match found in any of our font managers.\n        //\treturn null;\n        //  }\n\n        //  public minikin.FontFamily * MatchFallbackFont(uint ch, string locale)\n        //  {\n        //\tforeach (sk_sp<SkFontMgr> manager in GetFontManagerOrder())\n        //\t{\n        //\t  List<char> bcp47 = new List<char>();\n        //\t  if (!string.IsNullOrEmpty(locale))\n        //\t  {\n        //\t\tbcp47.Add(locale);\n        //\t  }\n        //\t  SKTypeface typeface = new SKTypeface(manager.matchFamilyStyleCharacter(0, SkFontStyle(), bcp47.data(), bcp47.Count, ch));\n        //\t  if (typeface == null)\n        //\t  {\n        //\t\tcontinue;\n        //\t  }\n\n        //\t  SkString sk_family_name = new SkString();\n        //\t  typeface.getFamilyName(sk_family_name);\n        //\t  string family_name = sk_family_name.c_str();\n\n        //\t  fallback_fonts_for_locale_[locale].Add(family_name);\n\n        //\t  return GetFallbackFontFamily(manager, family_name);\n        //\t}\n\n        //\treturn GlobalMembers.g_null_family;\n        //  }\n\n        //  // Do not provide alternative fonts that can match characters which are\n        //  // missing from the requested font family.\n        //  public void DisableFontFallback()\n        //  {\n        //\tenable_font_fallback_ = false;\n        //  }\n\n        //  private class FamilyKey\n        //  {\n        //\tpublic FamilyKey(string family, string loc)\n        //\t{\n        //\t\tthis.font_family = family;\n        //\t\tthis.locale = loc;\n        //\t}\n\n        //\tpublic string font_family;\n        //\tpublic string locale;\n\n        ////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        ////ORIGINAL LINE: bool operator ==(const FontCollection::FamilyKey& other) const\n        //\tpublic static bool operator == (FamilyKey ImpliedObject, FontCollection.FamilyKey other)\n        //\t{\n        //\t  return ImpliedObject.font_family == other.font_family && ImpliedObject.locale == other.locale;\n        //\t}\n\n        //\tpublic class Hasher\n        //\t{\n        ////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        ////ORIGINAL LINE: int operator ()(const FontCollection::FamilyKey& key) const\n        //\t  public static int functorMethod(FontCollection.FamilyKey key)\n        //\t  {\n        //\t\treturn std::hash<string>()(key.font_family) ^ std::hash<string>()(key.locale);\n        //\t  }\n        //\t}\n        //  }\n\n        //  private sk_sp<SkFontMgr> default_font_manager_ = new sk_sp<SkFontMgr>();\n        //  private sk_sp<SkFontMgr> asset_font_manager_ = new sk_sp<SkFontMgr>();\n        //  private sk_sp<SkFontMgr> dynamic_font_manager_ = new sk_sp<SkFontMgr>();\n        //  private sk_sp<SkFontMgr> test_font_manager_ = new sk_sp<SkFontMgr>();\n        //  private Dictionary<FamilyKey, minikin.FontCollection, FamilyKey.Hasher> font_collections_cache_ = new Dictionary<FamilyKey, minikin.FontCollection, FamilyKey.Hasher>();\n        //  private Dictionary<string, minikin.FontFamily> fallback_fonts_ = new Dictionary<string, minikin.FontFamily>();\n        //  private Dictionary<string, SortedSet<string>> fallback_fonts_for_locale_ = new Dictionary<string, SortedSet<string>>();\n        private bool enable_font_fallback_;\n\n\n        //  // Return the available font managers in the order they should be queried.\n        ////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        ////ORIGINAL LINE: ClassicVector<sk_sp<SkFontMgr>> GetFontManagerOrder() const\n        //  private List<sk_sp<SkFontMgr>> GetFontManagerOrder()\n        //  {\n        //\tList<sk_sp<SkFontMgr>> order = new List<sk_sp<SkFontMgr>>();\n        //\tif (test_font_manager_ != null)\n        //\t{\n        //\t  order.Add(test_font_manager_);\n        //\t}\n        //\tif (dynamic_font_manager_ != null)\n        //\t{\n        //\t  order.Add(dynamic_font_manager_);\n        //\t}\n        //\tif (asset_font_manager_ != null)\n        //\t{\n        //\t  order.Add(asset_font_manager_);\n        //\t}\n        //\tif (default_font_manager_ != null)\n        //\t{\n        //\t  order.Add(default_font_manager_);\n        //\t}\n        //\treturn order;\n        //  }\n\n        //  private minikin.FontFamily CreateMinikinFontFamily(sk_sp<SkFontMgr> manager, string family_name)\n        //  {\n        //\tsk_sp<SkFontStyleSet> font_style_set = new sk_sp<SkFontStyleSet>(manager.matchFamily(family_name));\n        //\tif (font_style_set == null || font_style_set.count() == 0)\n        //\t{\n        //\t  return null;\n        //\t}\n\n        //\tList<minikin.Font> minikin_fonts = new List<minikin.Font>();\n\n        //\t// Add fonts to the Minikin font family.\n        //\tfor (int i = 0; i < font_style_set.count(); ++i)\n        //\t{\n        //\t  // Create the skia typeface.\n        //\t  SKTypeface skia_typeface = new SKTypeface(SKTypeface(font_style_set.createTypeface(i)));\n        //\t  if (skia_typeface == null)\n        //\t  {\n        //\t\tcontinue;\n        //\t  }\n\n        //\t  // Create the minikin font from the skia typeface.\n        //\t  // Divide by 100 because the weights are given as \"100\", \"200\", etc.\n        //\t  minikin.Font minikin_font = new minikin.Font(new FontSkia(new SKTypeface(skia_typeface)), new minikin.FontStyle(new uint(skia_typeface.fontStyle().weight() / 100, skia_typeface.isItalic())));\n\n        //\t  minikin_fonts.Add(minikin_font);\n        //\t}\n\n        //\treturn new minikin.FontFamily(minikin_fonts);\n        //  }\n\n        //  private minikin.FontFamily * GetFallbackFontFamily(sk_sp<SkFontMgr> manager, string family_name)\n        //  {\n        //\tvar fallback_it = fallback_fonts_.find(family_name);\n        ////C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n        //\tif (fallback_it != fallback_fonts_.end())\n        //\t{\n        ////C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n        //\t  return fallback_it.second;\n        //\t}\n\n        //\tminikin.FontFamily minikin_family = CreateMinikinFontFamily(manager, family_name);\n        //\tif (minikin_family == null)\n        //\t{\n        //\t  return GlobalMembers.g_null_family;\n        //\t}\n\n        //\tvar insert_it = fallback_fonts_.Add(family_name, minikin_family);\n\n        //\t// Clear the cache to force creation of new font collections that will include\n        //\t// this fallback font.\n        //\tfont_collections_cache_.Clear();\n\n        //\treturn insert_it.first.second;\n        //  }\n\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //  FML_DISALLOW_COPY_AND_ASSIGN(FontCollection);\n        //}\n\n        //} // namespace FlutterBinding.Txt\n\n\n\n        ////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n        ////#include \"flutter/fml/logging.h\"\n\n        //namespace FlutterBinding.Txt\n        //{\n\n        ////C++ TO C# CONVERTER NOTE: C# does not allow anonymous namespaces:\n        ////namespace\n\n\n        //public class TxtFallbackFontProvider : minikin.FontCollection.FallbackFontProvider\n        //{\n        //  public TxtFallbackFontProvider(FontCollection font_collection)\n        //  {\n        //\t  this.font_collection_ = font_collection;\n        //  }\n\n        //  public override minikin.FontFamily * matchFallbackFont(uint ch, string locale)\n        //  {\n        //\tFontCollection fc = font_collection_.@lock();\n        //\tif (fc != null)\n        //\t{\n        //\t  return fc.MatchFallbackFont(ch, locale);\n        //\t}\n        //\telse\n        //\t{\n        //\t  return GlobalMembers.g_null_family;\n        //\t}\n        //  }\n\n        //  private std::weak_ptr<FontCollection> font_collection_ = new std::weak_ptr<FontCollection>();\n        //}\n\n        ////C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n        ////FontCollection::~FontCollection() = default;\n    }\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/font_skia.cs",
    "content": "﻿//using System.Collections.Generic;\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n///*\n// * Copyright 2017 Google Inc.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n\n////C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n////#include \"flutter/fml/macros.h\"\n\n//namespace FlutterBinding.Txt\n//{\n\n//public class FontSkia : minikin.MinikinFont, System.IDisposable\n//{\n//  public FontSkia(SKTypeface typeface) : base(typeface.uniqueID())\n//  {\n//\t  this.typeface_ = typeface;\n//  }\n\n////C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n////  public void Dispose();\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: float GetHorizontalAdvance(uint glyph_id, const minikin::MinikinPaint& paint) const override\n//  public override float GetHorizontalAdvance(uint glyph_id, minikin.MinikinPaint paint)\n//  {\n//\tSKPaint skPaint = new SKPaint();\n//\tUInt16 glyph16 = glyph_id;\n//\tSkScalar skWidth = new SkScalar();\n//\tGlobalMembers.FontSkia_SetSkiaPaint(new SKTypeface(typeface_), skPaint, paint);\n//\tskPaint.getTextWidths(glyph16, sizeof(UInt16), skWidth, null);\n//\treturn skWidth;\n//  }\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: void GetBounds(minikin::MinikinRect* bounds, uint glyph_id, const minikin::MinikinPaint& paint) const override\n//  public override void GetBounds(minikin.MinikinRect bounds, uint glyph_id, minikin.MinikinPaint paint)\n//  {\n//\tSKPaint skPaint = new SKPaint();\n//\tUInt16 glyph16 = glyph_id;\n//\tSkRect skBounds = new SkRect();\n//\tGlobalMembers.FontSkia_SetSkiaPaint(new SKTypeface(typeface_), skPaint, paint);\n//\tskPaint.getTextWidths(glyph16, sizeof(UInt16), null, skBounds);\n//\tbounds.mLeft = skBounds.Left;\n//\tbounds.mTop = skBounds.fTop;\n//\tbounds.mRight = skBounds.Right;\n//\tbounds.mBottom = skBounds.fBottom;\n//  }\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: HarfBuzzSharp.Face* CreateHarfBuzzFace() const override\n//  public override HarfBuzzSharp.Face CreateHarfBuzzFace()\n//  {\n//\treturn hb_face_create_for_tables(GlobalMembers.GetTable, typeface_.get(), 0);\n//  }\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: const ClassicVector<minikin::FontVariation>& GetAxes() const override\n//  public override List<minikin.FontVariation> GetAxes()\n//  {\n//\treturn variations_;\n//  }\n\n////C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n////ORIGINAL LINE: const SKTypeface& GetSkTypeface() const\n//  public SKTypeface GetSkTypeface()\n//  {\n//\treturn typeface_;\n//  }\n\n//  private SKTypeface typeface_ = new SKTypeface();\n//  private List<minikin.FontVariation> variations_ = new List<minikin.FontVariation>();\n\n////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n//  FML_DISALLOW_COPY_AND_ASSIGN(FontSkia);\n//}\n\n//} // namespace FlutterBinding.Txt\n\n\n\n//namespace FlutterBinding.Txt\n//{\n////C++ TO C# CONVERTER NOTE: C# does not allow anonymous namespaces:\n////namespace\n\n//} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/font_style.cs",
    "content": "﻿/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nnamespace FlutterBinding.Txt\n{\n\n    public enum FontStyle\n    {\n        normal,\n        italic,\n    }\n\n} // namespace FlutterBinding.Txt\n\n"
  },
  {
    "path": "FlutterBinding/Txt/font_weight.cs",
    "content": "﻿/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nnamespace FlutterBinding.Txt\n{\n\n    public enum FontWeight\n    {\n        w100, // Thin\n        w200, // Extra-Light\n        w300, // Light\n        w400, // Normal/Regular\n        w500, // Medium\n        w600, // Semi-bold\n        w700, // Bold\n        w800, // Extra-Bold\n        w900, // Black\n    }\n\n} // namespace FlutterBinding.Txt\n\n"
  },
  {
    "path": "FlutterBinding/Txt/paint_record.cs",
    "content": "﻿/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/macros.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WHEN(condition, T) skstd::enable_if_t<!!(condition), T>\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendScalar SkStrAppendFloat\n\nusing SkiaSharp;\n\nnamespace FlutterBinding.Txt\n{\n\n    // PaintRecord holds the layout data after Paragraph::Layout() is called. This\n    // stores all nessecary offsets, blobs, metrics, and more for Skia to draw the\n    // text.\n    public class PaintRecord //: System.IDisposable\n    {\n        //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n        //  PaintRecord() = delete;\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        public PaintRecord(TextStyle style, SKPoint offset, SkTextBlob text, SKFontMetrics metrics, int line, double run_width)\n        {\n            this.style_ = style;\n            this.offset_ = offset;\n            this.text_ = text;\n            this.metrics_ = metrics;\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.line_ = line;\n            this.line_ = line;\n            this.run_width_ = run_width;\n        }\n\n        public PaintRecord(TextStyle style, SkTextBlob text, SKFontMetrics metrics, int line, double run_width)\n        {\n            this.style_ = style;\n            this.text_ = text;\n            this.metrics_ = metrics;\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.line_ = line;\n            this.line_ = line;\n            this.run_width_ = run_width;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public PaintRecord(PaintRecord other)\n        {\n            style_ = other.style_;\n            offset_ = other.offset_;\n            text_ = other.text_;\n            metrics_ = other.metrics_;\n            line_ = other.line_;\n            run_width_ = other.run_width_;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        //C++ TO C# CONVERTER TODO TASK: The = operator cannot be overloaded in C#:\n        //public static PaintRecord operator = (PaintRecord && other)\n        //{\n        //    style_ = other.style_;\n        //    offset_ = other.offset_;\n        //    text_ = other.text_;\n        //    metrics_ = other.metrics_;\n        //    line_ = other.line_;\n        //    run_width_ = other.run_width_;\n        //    return this;\n        //}\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: SKPoint offset() const\n        public SKPoint offset()\n        {\n            return offset_;\n        }\n\n        public void SetOffset(SKPoint pt)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: offset_ = pt;\n            offset_ = pt;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: SkTextBlob* text() const\n        public SkTextBlob text()\n        {\n            return text_;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const SKPaint::FontMetrics& metrics() const\n        public SKFontMetrics metrics()\n        {\n            return metrics_;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const TextStyle& style() const\n        public TextStyle style()\n        {\n            return style_;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int line() const\n        public int line()\n        {\n            return line_;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetRunWidth() const\n        public double GetRunWidth()\n        {\n            return run_width_;\n        }\n\n        private TextStyle style_ = new TextStyle();\n        // offset_ is the overall offset of the origin of the SkTextBlob.\n        private SKPoint offset_ = new SKPoint();\n        // SkTextBlob stores the glyphs and coordinates to draw them.\n        private SkTextBlob text_ = new SkTextBlob();\n        // FontMetrics stores the measurements of the font used.\n        private SKFontMetrics metrics_ = new SKFontMetrics();\n        private int line_ = new int();\n        private double run_width_ = 0.0f;\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FML_DISALLOW_COPY_AND_ASSIGN(PaintRecord);\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n\nnamespace FlutterBinding.Txt\n{\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //PaintRecord::~PaintRecord() = default;\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/paragraph.cs",
    "content": "﻿using FlutterBinding.Txt;\nusing HarfBuzzSharp;\nusing SkiaSharp;\nusing System;\nusing System.Collections.Generic;\nusing static FlutterBinding.Txt.Paragraph;\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/compiler_specific.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/macros.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WHEN(condition, T) skstd::enable_if_t<!!(condition), T>\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendScalar SkStrAppendFloat\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/googletest/googletest/include/gtest/gtest_prod.h\" // nogncheck\n\n//C++ TO C# CONVERTER NOTE: C# has no need of forward class declarations:\n//class SKCanvas;\n\nnamespace FlutterBinding.Txt\n{\n\n\n    // Paragraph provides Layout, metrics, and painting capabilites for text. Once a\n    // Paragraph is constructed with ParagraphBuilder::Build(), an example basic\n    // workflow can be this:\n    //\n    //   std::unique_ptr<Paragraph> paragraph = paragraph_builder.Build();\n    //   paragraph->Layout(<somewidthgoeshere>);\n    //   paragraph->Paint(<someSKCanvas>, <xpos>, <ypos>);\n    public class Paragraph //: System.IDisposable\n    {\n        // Constructor. It is highly recommended to construct a paragraph with a\n        // ParagraphBuilder.\n        public Paragraph()\n        {\n            breaker_.setLocale(icu.Locale(), null);\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        public enum Affinity\n        {\n            UPSTREAM,\n            DOWNSTREAM\n        }\n\n        // Struct that holds calculated metrics for each line.\n        //C++ TO C# CONVERTER TODO TASK: C# does not allow declaring types within methods:\n        public class LineBoxMetrics\n        {\n            public List<TextBox> boxes;\n            // Per-line metrics for max and min coordinates for left and right boxes.\n            // These metrics cannot be calculated in layout generically because of\n            // selections that do not cover the whole line.\n            public float max_right;// = FLT_MIN;\n            public float min_left; //= FLT_MAX;\n        };\n\n\n        // TODO(garyq): Implement kIncludeLineSpacing and kExtendEndOfLine\n\n        // Options for various types of bounding boxes provided by\n        // GetRectsForRange(...).\n        public enum RectHeightStyle\n        {\n            // Provide tight bounding boxes that fit heights per run.\n            kTight,\n\n            // The height of the boxes will be the maximum height of all runs in the\n            // line. All rects in the same line will be the same height.\n            kMax,\n\n            // Extends the top and/or bottom edge of the bounds to fully cover any line\n            // spacing. The top edge of each line should be the same as the bottom edge\n            // of the line above. There should be no gaps in vertical coverage given any\n            // ParagraphStyle line_height.\n            //\n            // The top and bottom of each rect will cover half of the\n            // space above and half of the space below the line.\n            kIncludeLineSpacingMiddle,\n            // The line spacing will be added to the top of the rect.\n            kIncludeLineSpacingTop,\n            // The line spacing will be added to the bottom of the rect.\n            kIncludeLineSpacingBottom\n        }\n\n        public enum RectWidthStyle\n        {\n            // Provide tight bounding boxes that fit widths to the runs of each line\n            // independently.\n            kTight,\n\n            // Extends the width of the last rect of each line to match the position of\n            // the widest rect over all the lines.\n            kMax\n        }\n\n        public class PositionWithAffinity\n        {\n            public readonly int position = new int();\n            public readonly Affinity affinity;\n\n            public PositionWithAffinity(int p, Affinity a)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.position = p;\n                this.position = p;\n                this.affinity = a;\n            }\n        }\n\n        public class TextBox\n        {\n            public SKRect rect = new SKRect();\n            public TextDirection direction;\n\n            public TextBox(SKRect r, TextDirection d)\n            {\n                this.rect = r;\n                this.direction = d;\n            }\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The original C++ template specifier was replaced with a C# generic specifier, which may not produce the same behavior:\n        //ORIGINAL LINE: template <typename T>\n        public class Range<T> where T : struct\n        {\n            public Range()\n            {\n                this.start = default(T);\n                this.end = default(T);\n            }\n            public Range(T s, T e)\n            {\n                this.start = s;\n                this.end = e;\n            }\n\n            public T start = new T();\n            public T end = new T();\n\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: bool operator ==(const Range<T>& other) const\n            //public static bool operator ==(Range ImpliedObject, Range<T> other)\n            //{\n            //    return ImpliedObject.start == other.start && ImpliedObject.end == other.end;\n            //}\n\n            public T width()\n            {\n                return end - start;\n            }\n\n            public void Shift(T delta)\n            {\n                start += delta;\n                end += delta;\n            }\n        }\n\n        // Minikin Layout doLayout() and LineBreaker addStyleRun() has an\n        // O(N^2) (according to benchmarks) time complexity where N is the total\n        // number of characters. However, this is not significant for reasonably sized\n        // paragraphs. It is currently recommended to break up very long paragraphs\n        // (10k+ characters) to ensure speedy layout.\n        //\n        // Layout calculates the positioning of all the glyphs. Must call this method\n        // before Painting and getting any statistics from this class.\n        public void Layout(double width, bool force = false)\n        {\n            // Do not allow calling layout multiple times without changing anything.\n            if (!needs_layout_ && width == width_ && !force)\n            {\n                return;\n            }\n            needs_layout_ = false;\n\n            width_ = Math.Floor(width);\n\n            if (!ComputeLineBreaks())\n            {\n                return;\n            }\n\n            List<BidiRun> bidi_runs = new List<BidiRun>();\n            if (!ComputeBidiRuns(bidi_runs))\n            {\n                return;\n            }\n\n            SKPaint paint = new SKPaint();\n            paint.setAntiAlias(true);\n            paint.setTextEncoding(SKPaint.TextEncoding.kGlyphID_TextEncoding);\n            paint.setSubpixelText(true);\n            paint.HintingLevel = SKPaintHinting.Slight; // SetHinting(SKPaint.Hinting.kSlight_Hinting);\n\n            records_.Clear();\n            line_heights_.Clear();\n            line_baselines_.Clear();\n            glyph_lines_.Clear();\n            code_unit_runs_.Clear();\n            line_max_spacings_.Clear();\n            line_max_descent_.Clear();\n            line_max_ascent_.Clear();\n            max_right_ = double.MinValue; // FLT_MIN;\n            min_left_ = double.MaxValue; // FLT_MAX;\n\n            minikin.Layout layout = new minikin.Layout();\n            SkTextBlobBuilder builder = new SkTextBlobBuilder();\n            double y_offset = 0;\n            double prev_max_descent = 0;\n            double max_word_width = 0;\n\n            int line_limit = Math.Min(paragraph_style_.max_lines, line_ranges_.Count);\n            did_exceed_max_lines_ = (line_ranges_.Count > paragraph_style_.max_lines);\n\n            for (int line_number = 0; line_number < line_limit; ++line_number)\n            {\n                LineRange line_range = line_ranges_[line_number];\n\n                // Break the line into words if justification should be applied.\n                List<Range<int>> words = new List<Range<int>>();\n                double word_gap_width = 0;\n                int word_index = 0;\n                bool justify_line = (paragraph_style_.text_align == TextAlign.justify && line_number != line_limit - 1 && !line_range.hard_break);\n                GlobalMembers.FindWords(text_, line_range.start, line_range.end, words);\n                if (justify_line)\n                {\n                    if (words.Count > 1)\n                    {\n                        word_gap_width = (width_ - line_widths_[line_number]) / (words.Count - 1);\n                    }\n                }\n\n                // Exclude trailing whitespace from right-justified lines so the last\n                // visible character in the line will be flush with the right margin.\n                int line_end_index = (paragraph_style_.effective_align() == TextAlign.right || paragraph_style_.effective_align() == TextAlign.center) ? line_range.end_excluding_whitespace : line_range.end;\n\n                // Find the runs comprising this line.\n                List<BidiRun> line_runs = new List<BidiRun>();\n                foreach (BidiRun bidi_run in bidi_runs)\n                {\n                    if (bidi_run.start() < line_end_index && bidi_run.end() > line_range.start)\n                    {\n                        line_runs.Add(Math.Max(bidi_run.start(), line_range.start), Math.Min(bidi_run.end(), line_end_index), bidi_run.direction(), bidi_run.style());\n                    }\n                }\n\n                List<GlyphPosition> line_glyph_positions = new List<GlyphPosition>();\n                List<CodeUnitRun> line_code_unit_runs = new List<CodeUnitRun>();\n                double run_x_offset = 0;\n                double justify_x_offset = 0;\n                List<PaintRecord> paint_records = new List<PaintRecord>();\n\n                foreach (BidiRun line_run_it in line_runs)\n                {\n                    //C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to references to variables:\n                    //ORIGINAL LINE: const BidiRun& run = line_run_it;\n                    BidiRun run = line_run_it;\n                    minikin.FontStyle font = new minikin.FontStyle();\n                    minikin.MinikinPaint minikin_paint = new minikin.MinikinPaint();\n                    GlobalMembers.GetFontAndMinikinPaint(run.style(), font, minikin_paint);\n                    paint.setTextSize(run.style().font_size);\n\n                    minikin.FontCollection minikin_font_collection = GetMinikinFontCollectionForStyle(run.style());\n\n                    // Lay out this run.\n                    UInt16 text_ptr = text_.data();\n                    int text_start = run.start();\n                    int text_count = run.end() - run.start();\n                    int text_size = text_.Count;\n\n                    // Apply ellipsizing if the run was not completely laid out and this\n                    // is the last line (or lines are unlimited).\n                    var ellipsis = paragraph_style_.ellipsis;\n                    List<UInt16> ellipsized_text = new List<UInt16>();\n                    if (ellipsis.length() && !double.IsInfinity(width_) && !line_range.hard_break && line_run_it == line_runs.end() - 1 && (line_number == line_limit - 1 || paragraph_style_.unlimited_lines()))\n                    {\n                        //C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n                        float ellipsis_width = layout.measureText(ellipsis.data(), 0, ellipsis.length(), ellipsis.length(), run.is_rtl(), font, minikin_paint, minikin_font_collection, null);\n\n                        List<float> text_advances = new List<float>(text_count);\n                        float text_width = layout.measureText(text_ptr, text_start, text_count, text_.Count, run.is_rtl(), font, minikin_paint, minikin_font_collection, text_advances.data());\n\n                        // Truncate characters from the text until the ellipsis fits.\n                        int truncate_count = 0;\n                        while (truncate_count < text_count && run_x_offset + text_width + ellipsis_width > width_)\n                        {\n                            text_width -= text_advances[text_count - truncate_count - 1];\n                            truncate_count++;\n                        }\n\n                        ellipsized_text.Capacity = text_count - truncate_count + ellipsis.length();\n                        //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent to the STL vector 'insert' method in C#:\n                        ellipsized_text.insert(ellipsized_text.GetEnumerator(), text_.GetEnumerator() + run.start(), text_.GetEnumerator() + run.end() - truncate_count);\n                        ellipsized_text.AddRange(ellipsis);\n                        text_ptr = ellipsized_text.data();\n                        text_start = 0;\n                        text_count = ellipsized_text.Count;\n                        //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                        //ORIGINAL LINE: text_size = text_count;\n                        text_size = text_count;\n\n                        // If there is no line limit, then skip all lines after the ellipsized\n                        // line.\n                        if (paragraph_style_.unlimited_lines())\n                        {\n                            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                            //ORIGINAL LINE: line_limit = line_number + 1;\n                            line_limit = line_number + 1;\n                            did_exceed_max_lines_ = true;\n                        }\n                    }\n\n                    layout.doLayout(text_ptr, text_start, text_count, text_size, run.is_rtl(), font, minikin_paint, minikin_font_collection);\n\n                    if (layout.nGlyphs() == 0)\n                    {\n                        continue;\n                    }\n\n                    List<float> layout_advances = new List<float>(text_count);\n                    layout.getAdvances(layout_advances.data());\n\n                    // Break the layout into blobs that share the same SKPaint parameters.\n                    List<Range<int>> glyph_blobs = GlobalMembers.GetLayoutTypefaceRuns(layout);\n\n                    double word_start_position = numeric_limits<double>.quiet_NaN();\n\n                    // Build a Skia text blob from each group of glyphs.\n                    foreach (Range<int> glyph_blob in glyph_blobs)\n                    {\n                        List<GlyphPosition> glyph_positions = new List<GlyphPosition>();\n\n                        GlobalMembers.GetGlyphTypeface(layout, glyph_blob.start).apply(paint);\n                        SkTextBlobBuilder.RunBuffer blob_buffer = builder.allocRunPos(paint, glyph_blob.end - glyph_blob.start);\n\n                        for (int glyph_index = glyph_blob.start; glyph_index < glyph_blob.end;)\n                        {\n                            int cluster_start_glyph_index = glyph_index;\n                            uint cluster = layout.getGlyphCluster(cluster_start_glyph_index);\n                            double glyph_x_offset;\n\n                            // Add all the glyphs in this cluster to the text blob.\n                            do\n                            {\n                                int blob_index = glyph_index - glyph_blob.start;\n                                blob_buffer.glyphs[blob_index] = layout.getGlyphId(glyph_index);\n\n                                int pos_index = blob_index * 2;\n                                blob_buffer.pos[pos_index] = layout.getX(glyph_index) + justify_x_offset;\n                                blob_buffer.pos[pos_index + 1] = layout.getY(glyph_index);\n\n                                if (glyph_index == cluster_start_glyph_index)\n                                {\n                                    glyph_x_offset = blob_buffer.pos[pos_index];\n                                }\n\n                                glyph_index++;\n                            } while (glyph_index < glyph_blob.end && layout.getGlyphCluster(glyph_index) == cluster);\n\n                            Range<int> glyph_code_units = new Range<int>((int)cluster, 0);\n                            List<int> grapheme_code_unit_counts = new List<int>();\n                            if (run.is_rtl())\n                            {\n                                if (cluster_start_glyph_index > 0)\n                                {\n                                    glyph_code_units.end = layout.getGlyphCluster(cluster_start_glyph_index - 1);\n                                }\n                                else\n                                {\n                                    glyph_code_units.end = text_count;\n                                }\n                                grapheme_code_unit_counts.Add(glyph_code_units.width());\n                            }\n                            else\n                            {\n                                if (glyph_index < layout.nGlyphs())\n                                {\n                                    glyph_code_units.end = layout.getGlyphCluster(glyph_index);\n                                }\n                                else\n                                {\n                                    glyph_code_units.end = text_count;\n                                }\n\n                                // The glyph may be a ligature.  Determine how many graphemes are\n                                // joined into this glyph and how many input code units map to\n                                // each grapheme.\n                                int code_unit_count = 1;\n                                for (int offset = glyph_code_units.start + 1; offset < glyph_code_units.end; ++offset)\n                                {\n                                    if (minikin.GraphemeBreak.isGraphemeBreak(layout_advances.data(), text_ptr, text_start, text_count, offset))\n                                    {\n                                        grapheme_code_unit_counts.Add(code_unit_count);\n                                        code_unit_count = 1;\n                                    }\n                                    else\n                                    {\n                                        code_unit_count++;\n                                    }\n                                }\n                                grapheme_code_unit_counts.Add(code_unit_count);\n                            }\n                            float glyph_advance = layout.getCharAdvance(glyph_code_units.start);\n                            float grapheme_advance = glyph_advance / grapheme_code_unit_counts.Count;\n\n                            glyph_positions.Add(run_x_offset + glyph_x_offset, grapheme_advance, run.start() + glyph_code_units.start, grapheme_code_unit_counts[0]);\n\n                            // Compute positions for the additional graphemes in the ligature.\n                            for (int i = 1; i < grapheme_code_unit_counts.Count; ++i)\n                            {\n                                glyph_positions.Add(glyph_positions[glyph_positions.Count - 1].x_pos.end, grapheme_advance, glyph_positions[glyph_positions.Count - 1].code_units.start + grapheme_code_unit_counts[i - 1], grapheme_code_unit_counts[i]);\n                            }\n\n                            if (word_index < words.Count && words[word_index].start == run.start() + glyph_code_units.start)\n                            {\n                                word_start_position = run_x_offset + glyph_x_offset;\n                            }\n\n                            if (word_index < words.Count && words[word_index].end == run.start() + glyph_code_units.end)\n                            {\n                                if (justify_line)\n                                {\n                                    justify_x_offset += word_gap_width;\n                                }\n                                word_index++;\n\n                                if (!double.IsNaN(word_start_position))\n                                {\n                                    double word_width = glyph_positions[glyph_positions.Count - 1].x_pos.end - word_start_position;\n                                    max_word_width = Math.Max(word_width, max_word_width);\n                                    word_start_position = numeric_limits<double>.quiet_NaN();\n                                }\n                            }\n                        } // for each in glyph_blob\n\n                        if (glyph_positions.Count == 0)\n                        {\n                            continue;\n                        }\n                        SKFontMetrics metrics = new SKFontMetrics();\n                        paint.getFontMetrics(metrics);\n                        paint_records.Add(run.style(), SKPoint.Make(run_x_offset, 0), builder.make(), metrics, line_number, layout.getAdvance());\n\n                        line_glyph_positions.AddRange(glyph_positions);\n\n                        // Add a record of glyph positions sorted by code unit index.\n                        List<GlyphPosition> code_unit_positions = new List<GlyphPosition>(glyph_positions);\n                        //C++ TO C# CONVERTER TODO TASK: The 'Compare' parameter of std::sort produces a boolean value, while the .NET Comparison parameter produces a tri-state result:\n                        //ORIGINAL LINE: std::sort(code_unit_positions.begin(), code_unit_positions.end(), [](const GlyphPosition& a, const GlyphPosition& b)\n                        code_unit_positions.Sort((GlyphPosition a, GlyphPosition b) =>\n                                  {\n                                      return a.code_units.start < b.code_units.start;\n                                  });\n                        line_code_unit_runs.Add(new CodeUnitRun(code_unit_positions, new Range<int>(run.start(), run.end()), new Range<double>(glyph_positions[0].x_pos.start, glyph_positions[glyph_positions.Count - 1].x_pos.end), line_number, metrics, run.direction()));\n\n                        min_left_ = Math.Min(min_left_, glyph_positions[0].x_pos.start);\n                        max_right_ = Math.Max(max_right_, glyph_positions[glyph_positions.Count - 1].x_pos.end);\n                    } // for each in glyph_blobs\n\n                    run_x_offset += layout.getAdvance();\n                } // for each in line_runs\n\n                // Adjust the glyph positions based on the alignment of the line.\n                double line_x_offset = GetLineXOffset(run_x_offset);\n                if ((int)line_x_offset != 0)\n                {\n                    foreach (CodeUnitRun code_unit_run in line_code_unit_runs)\n                    {\n                        code_unit_run.Shift(line_x_offset);\n                    }\n                    foreach (GlyphPosition position in line_glyph_positions)\n                    {\n                        position.Shift(line_x_offset);\n                    }\n                }\n\n                int next_line_start = (line_number < line_ranges_.Count - 1) ? line_ranges_[line_number + 1].start : text_.Count;\n                glyph_lines_.Add(new GlyphLine(line_glyph_positions, next_line_start - line_range.start));\n                code_unit_runs_.AddRange(line_code_unit_runs);\n\n                double max_line_spacing = 0;\n                double max_descent = 0;\n                float max_unscaled_ascent = 0F;\n                //C++ TO C# CONVERTER TODO TASK: Lambda expressions cannot be assigned to 'var':\n                Action<SKFontMetrics, TextStyle> update_line_metrics = (SKFontMetrics metrics, TextStyle style) =>\n                {\n                    // TODO(garyq): Multipling in the style.height on the first line is\n                    // probably wrong. Figure out how paragraph and line heights are supposed\n                    // to work and fix it.\n                    double line_spacing = (line_number == 0) ? -metrics.Ascent * style.height : (-metrics.Ascent + metrics.Leading) * style.height;\n                    if (line_spacing > max_line_spacing)\n                    {\n                        max_line_spacing = line_spacing;\n                        if (line_number == 0)\n                        {\n                            alphabetic_baseline_ = line_spacing;\n                            ideographic_baseline_ = (metrics.Descent - metrics.Ascent) * style.height;\n                        }\n                    }\n                    max_line_spacing = Math.Max(line_spacing, max_line_spacing);\n\n                    double descent = metrics.Descent * style.height;\n                    max_descent = Math.Max(descent, max_descent);\n\n                    max_unscaled_ascent = Math.Max(-metrics.Ascent, max_unscaled_ascent);\n                };\n\n                foreach (PaintRecord paint_record in paint_records)\n                {\n                    update_line_metrics(paint_record.metrics(), paint_record.style());\n                }\n                // If no fonts were actually rendered, then compute a baseline based on the\n                // font of the paragraph style.\n                if (paint_records.Count == 0)\n                {\n                    SKFontMetrics metrics = new SKFontMetrics();\n                    TextStyle style = paragraph_style_.GetTextStyle();\n                    paint.setTypeface(GetDefaultSkiaTypeface(style));\n                    paint.setTextSize(style.font_size);\n                    paint.getFontMetrics(metrics);\n                    update_line_metrics(metrics, style);\n                }\n\n                // TODO(garyq): Remove rounding of line heights because it is irrelevant in\n                // a world of high DPI devices.\n                line_heights_.Add((line_heights_.Count == 0 ? 0 : line_heights_[line_heights_.Count - 1]) + Math.Round(max_line_spacing + max_descent));\n                line_baselines_.Add(line_heights_[line_heights_.Count - 1] - max_descent);\n                y_offset += Math.Round(max_line_spacing + prev_max_descent);\n                prev_max_descent = max_descent;\n\n                // The max line spacing and ascent have been multiplied by -1 to make math\n                // in GetRectsForRange more logical/readable.\n                line_max_spacings_.Add(max_line_spacing);\n                line_max_descent_.Add(max_descent);\n                line_max_ascent_.Add(max_unscaled_ascent);\n\n                foreach (PaintRecord paint_record in paint_records)\n                {\n                    paint_record.SetOffset(SKPoint.Make(paint_record.Offset().x() + line_x_offset, y_offset));\n                    records_.Add(paint_record);\n                }\n            } // for each line_number\n\n            if (paragraph_style_.max_lines == 1 || (paragraph_style_.unlimited_lines() && paragraph_style_.ellipsized()))\n            {\n                min_intrinsic_width_ = max_intrinsic_width_;\n            }\n            else\n            {\n                min_intrinsic_width_ = Math.Min(max_word_width, max_intrinsic_width_);\n            }\n\n            //C++ TO C# CONVERTER TODO TASK: The 'Compare' parameter of std::sort produces a boolean value, while the .NET Comparison parameter produces a tri-state result:\n            //ORIGINAL LINE: std::sort(code_unit_runs_.begin(), code_unit_runs_.end(), [](const CodeUnitRun& a, const CodeUnitRun& b)\n            code_unit_runs_.Sort((CodeUnitRun a, CodeUnitRun b) =>\n            {\n                return a.code_units.start < b.code_units.start;\n            });\n        }\n\n        // Paints the Laid out text onto the supplied SKCanvas at (x, y) offset from\n        // the origin. Only valid after Layout() is called.\n\n        // The x,y coordinates will be the very top left corner of the rendered\n        // paragraph.\n        public void Paint(SKCanvas canvas, double x, double y)\n        {\n            SKPoint base_offset = new SKPoint((float)x, (float)y);\n            SKPaint paint = new SKPaint();\n            foreach (PaintRecord record in records_)\n            {\n                if (record.style().has_foreground)\n                {\n                    paint = record.style().foreground;\n                }\n                else\n                {\n                    paint.reset();\n                    paint.setColor(record.style().color);\n                }\n                SKPoint offset = base_offset + record.offset();\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n                //ORIGINAL LINE: PaintBackground(canvas, record, base_offset);\n                PaintBackground(canvas, record, base_offset);\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n                //ORIGINAL LINE: PaintShadow(canvas, record, offset);\n                PaintShadow(canvas, record, offset);\n                canvas.DrawText(record.text(), offset.X, offset.Y, paint);\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n                //ORIGINAL LINE: PaintDecorations(canvas, record, base_offset);\n                PaintDecorations(canvas, record, base_offset);\n            }\n        }\n\n        // Getter for paragraph_style_.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const ParagraphStyle& GetParagraphStyle() const\n        public ParagraphStyle GetParagraphStyle()\n        {\n            return paragraph_style_;\n        }\n\n        // Returns the number of characters/unicode characters. AKA text_.size()\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int TextSize() const\n        public int TextSize()\n        {\n            return text_.Count;\n        }\n\n        // Returns the height of the laid out paragraph. NOTE this is not a tight\n        // bounding height of the glyphs, as some glyphs do not reach as low as they\n        // can.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetHeight() const\n        public double GetHeight()\n        {\n            return line_heights_.Count > 0 ? line_heights_[line_heights_.Count - 1] : 0;\n        }\n\n        // Returns the width provided in the Layout() method. This is the maximum\n        // width any line in the laid out paragraph can occupy. We expect that\n        // GetMaxWidth() >= GetLayoutWidth().\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetMaxWidth() const\n        public double GetMaxWidth()\n        {\n            return width_;\n        }\n\n        // Distance from top of paragraph to the Alphabetic baseline of the first\n        // line. Used for alphabetic fonts (A-Z, a-z, greek, etc.)\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetAlphabeticBaseline() const\n        public double GetAlphabeticBaseline()\n        {\n            // Currently -fAscent\n            return alphabetic_baseline_;\n        }\n\n        // Distance from top of paragraph to the Ideographic baseline of the first\n        // line. Used for ideographic fonts (Chinese, Japanese, Korean, etc.)\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetIdeographicBaseline() const\n        public double GetIdeographicBaseline()\n        {\n            // TODO(garyq): Currently -fAscent + fUnderlinePosition. Verify this.\n            return ideographic_baseline_;\n        }\n\n        // Returns the total width covered by the paragraph without linebreaking.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetMaxIntrinsicWidth() const\n        public double GetMaxIntrinsicWidth()\n        {\n            return max_intrinsic_width_;\n        }\n\n        // Currently, calculated similarly to as GetLayoutWidth(), however this is not\n        // nessecarily 100% correct in all cases.\n        //\n        // Returns the actual max width of the longest line after Layout().\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: double GetMinIntrinsicWidth() const\n        public double GetMinIntrinsicWidth()\n        {\n            return min_intrinsic_width_;\n        }\n\n        // Returns a vector of bounding boxes that enclose all text between start and\n        // end glyph indexes, including start and excluding end.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: ClassicVector<Paragraph::TextBox> GetRectsForRange(int start, int end, RectHeightStyle rect_height_style, RectWidthStyle rect_width_style) const\n        public List<Paragraph.TextBox> GetRectsForRange(int start, int end, RectHeightStyle rect_height_style, RectWidthStyle rect_width_style)\n        {\n\n\n            SortedDictionary<int, LineBoxMetrics> line_metrics = new SortedDictionary<int, LineBoxMetrics>();\n            // Text direction of the first line so we can extend the correct side for\n            // RectWidthStyle::kMax.\n            TextDirection first_line_dir = TextDirection.ltr;\n\n            // Lines that are actually in the requested range.\n            int max_line = 0;\n            int min_line = int.MaxValue;// INT_MAX;\n\n            // Generate initial boxes and calculate metrics.\n            foreach (CodeUnitRun run in code_unit_runs_)\n            {\n                // Check to see if we are finished.\n                if (run.code_units.start >= end)\n                {\n                    break;\n                }\n                if (run.code_units.end <= start)\n                {\n                    continue;\n                }\n\n                double baseline = line_baselines_[run.line_number];\n                float top = (float)baseline + run.font_metrics.Ascent;\n                float bottom = (float)baseline + run.font_metrics.Descent;\n\n                max_line = Math.Max(run.line_number, max_line);\n                min_line = Math.Min(run.line_number, min_line);\n\n                // Calculate left and right.\n                float left;\n                float right;\n                if (run.code_units.start >= start && run.code_units.end <= end)\n                {\n                    left = (float)run.x_pos.start;\n                    right = (float)run.x_pos.end;\n                }\n                else\n                {\n                    left = 3.402823466e+38f;\n                    right = (-3.402823466e+38f);\n                    foreach (GlyphPosition gp in run.positions)\n                    {\n                        if (gp.code_units.start >= start && gp.code_units.end <= end)\n                        {\n                            left = Math.Min(left, (float)gp.x_pos.start);\n                            right = Math.Max(right, (float)gp.x_pos.end);\n                        }\n                    }\n                    if (left == 3.402823466e+38f || right == (-SK_ScalarMax))\n                    {\n                        continue;\n                    }\n                }\n                // Keep track of the min and max horizontal coordinates over all lines. Not\n                // needed for kTight.\n                if (rect_width_style == RectWidthStyle.kMax)\n                {\n                    line_metrics[run.line_number].max_right = Math.Max(line_metrics[run.line_number].max_right, right);\n                    line_metrics[run.line_number].min_left = Math.Min(line_metrics[run.line_number].min_left, left);\n                    if (min_line == run.line_number)\n                    {\n                        first_line_dir = run.direction;\n                    }\n                }\n                line_metrics[run.line_number].boxes.Add(new TextBox(new SKRect(left, top, right, bottom), run.direction));\n            }\n\n            // Add empty rectangles representing any newline characters within the\n            // range.\n            for (int line_number = 0; line_number < line_ranges_.Count; ++line_number)\n            {\n                LineRange line = line_ranges_[line_number];\n                if (line.start >= end)\n                {\n                    break;\n                }\n                if (line.end_including_newline <= start)\n                {\n                    continue;\n                }\n                if (!line_metrics.ContainsKey(line_number))\n                {\n                    if (line.end != line.end_including_newline && line.end >= start && line.end_including_newline <= end)\n                    {\n                        float x = (float)line_widths_[line_number];\n                        float top = (line_number > 0) ? line_heights_[line_number - 1] : 0F;\n                        float bottom = (float)line_heights_[line_number];\n                        line_metrics[line_number].boxes.Add(new TextBox(new SKRect(x, top, x, bottom), TextDirection.ltr));\n                    }\n                }\n            }\n\n            // \"Post-process\" metrics and aggregate final rects to return.\n            List<Paragraph.TextBox> boxes = new List<Paragraph.TextBox>();\n            foreach (var kv in line_metrics)\n            {\n                // Handle rect_width_styles. We skip the last line because not everything is\n                // selected.\n                if (rect_width_style == RectWidthStyle.kMax && kv.Key != max_line)\n                {\n                    if (line_metrics[kv.Key].min_left > min_left_ && (kv.Key != min_line || first_line_dir == TextDirection.rtl))\n                    {\n                        line_metrics[kv.Key].boxes.Add(new TextBox(new SKRect((float)min_left_, (float)(line_baselines_[kv.Key] - line_max_ascent_[kv.Key]), line_metrics[kv.Key].min_left, (float)line_baselines_[kv.Key] + line_max_descent_[kv.Key]), TextDirection.rtl));\n                    }\n                    if (line_metrics[kv.Key].max_right < max_right_ && (kv.Key != min_line || first_line_dir == TextDirection.ltr))\n                    {\n                        line_metrics[kv.Key].boxes.Add(new TextBox(new SKRect(line_metrics[kv.Key].max_right, (float)(line_baselines_[kv.Key] - line_max_ascent_[kv.Key]), (float)max_right_, (float)line_baselines_[kv.Key] + line_max_descent_[kv.Key]), TextDirection.ltr));\n                    }\n                }\n\n                // Handle rect_height_styles. The height metrics used are all positive to\n                // make the signage clear here.\n                if (rect_height_style == RectHeightStyle.kTight)\n                {\n                    // Ignore line max height and width and generate tight bounds.\n                    boxes.AddRange(kv.Value.boxes);\n                }\n                else if (rect_height_style == RectHeightStyle.kMax)\n                {\n                    foreach (var box in kv.Value.boxes)\n                    {\n                        boxes.Add(new TextBox(new SKRect(box.rect.Left, (float)line_baselines_[kv.Key] - line_max_ascent_[kv.Key], box.rect.Right, (float)(line_baselines_[kv.Key] + line_max_descent_[kv.Key])), box.direction));\n                    }\n                }\n                else if (rect_height_style == RectHeightStyle.kIncludeLineSpacingMiddle)\n                {\n                    float adjusted_bottom = line_baselines_[kv.Key] + line_max_descent_[kv.Key];\n                    if (kv.Key < line_ranges_.Count - 1)\n                    {\n                        adjusted_bottom += (line_max_spacings_[kv.Key + 1] - line_max_ascent_[kv.Key + 1]) / 2;\n                    }\n                    float adjusted_top = line_baselines_[kv.Key] - line_max_ascent_[kv.Key];\n                    if (kv.Key != 0)\n                    {\n                        adjusted_top -= (line_max_spacings_[kv.Key] - line_max_ascent_[kv.Key]) / 2;\n                    }\n                    foreach (var box in kv.Value.boxes)\n                    {\n                        boxes.Add(new TextBox(new SKRect(box.rect.Left, adjusted_top, box.rect.Right, adjusted_bottom), box.direction));\n                    }\n                }\n                else if (rect_height_style == RectHeightStyle.kIncludeLineSpacingTop)\n                {\n                    foreach (var box in kv.Value.boxes)\n                    {\n                        float adjusted_top = kv.Key == 0 ? line_baselines_[kv.Key] - line_max_ascent_[kv.Key] : line_baselines_[kv.Key] - line_max_spacings_[kv.Key];\n                        boxes.Add(new TextBox(new SKRect(box.rect.Left, adjusted_top, box.rect.Right, line_baselines_[kv.Key] + line_max_descent_[kv.Key]), box.direction));\n                    }\n                }\n                else\n                { // kIncludeLineSpacingBottom\n                    foreach (var box in kv.Value.boxes)\n                    {\n                        float adjusted_bottom = (float)line_baselines_[kv.Key] + line_max_descent_[kv.Key];\n                        if (kv.Key < line_ranges_.Count - 1)\n                        {\n                            adjusted_bottom += -line_max_ascent_[kv.Key] + line_max_spacings_[kv.Key];\n                        }\n                        boxes.Add(new TextBox(new SKRect(box.rect.Left, (float)(line_baselines_[kv.Key] - line_max_ascent_[kv.Key]), box.rect.Right, adjusted_bottom), box.direction));\n                    }\n                }\n            }\n            return boxes;\n        }\n\n        // Returns the index of the glyph that corresponds to the provided coordinate,\n        // with the top left corner as the origin, and +y direction as down.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: Paragraph::PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, double dy) const\n        public Paragraph.PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, double dy)\n        {\n            if (line_heights_.Count == 0)\n            {\n                return new PositionWithAffinity(0, Affinity.DOWNSTREAM);\n            }\n\n            int y_index = new int();\n            for (y_index = 0; y_index < line_heights_.Count - 1; ++y_index)\n            {\n                if (dy < line_heights_[y_index])\n                {\n                    break;\n                }\n            }\n\n            List<GlyphPosition> line_glyph_position = glyph_lines_[y_index].positions;\n            if (line_glyph_position.Count == 0)\n            {\n                int line_start_index = std::accumulate(glyph_lines_.GetEnumerator(), glyph_lines_.GetEnumerator() + y_index, 0, (int a, GlyphLine b) =>\n                {\n                    return a + (int)b.total_code_units;\n                });\n                return new PositionWithAffinity(line_start_index, Affinity.DOWNSTREAM);\n            }\n\n            int x_index = new int();\n            GlyphPosition gp = null;\n            for (x_index = 0; x_index < line_glyph_position.Count; ++x_index)\n            {\n                double glyph_end = (x_index < line_glyph_position.Count - 1) ? line_glyph_position[x_index + 1].x_pos.start : line_glyph_position[x_index].x_pos.end;\n                if (dx < glyph_end)\n                {\n                    gp = line_glyph_position[x_index];\n                    break;\n                }\n            }\n\n            if (gp == null)\n            {\n                GlyphPosition last_glyph = line_glyph_position[line_glyph_position.Count - 1];\n                return new PositionWithAffinity(last_glyph.code_units.end, Affinity.UPSTREAM);\n            }\n\n            // Find the direction of the run that contains this glyph.\n            TextDirection direction = TextDirection.ltr;\n            foreach (CodeUnitRun run in code_unit_runs_)\n            {\n                if (gp.code_units.start >= run.code_units.start && gp.code_units.end <= run.code_units.end)\n                {\n                    direction = run.direction;\n                    break;\n                }\n            }\n\n            double glyph_center = (gp.x_pos.start + gp.x_pos.end) / 2;\n            if ((direction == TextDirection.ltr && dx < glyph_center) || (direction == TextDirection.rtl && dx >= glyph_center))\n            {\n                return new PositionWithAffinity(gp.code_units.start, Affinity.DOWNSTREAM);\n            }\n            else\n            {\n                return new PositionWithAffinity(gp.code_units.end, Affinity.UPSTREAM);\n            }\n        }\n\n        // Finds the first and last glyphs that define a word containing the glyph at\n        // index offset.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: Paragraph::Range<int> GetWordBoundary(int offset) const\n        public Paragraph.Range<int> GetWordBoundary(int offset)\n        {\n            if (text_.Count == 0)\n            {\n                return new Range<int>(0, 0);\n            }\n\n            if (word_breaker_ == null)\n            {\n                UErrorCode status = U_ZERO_ERROR;\n                word_breaker_.reset(icu.BreakIterator.createWordInstance(icu.Locale(), status));\n                if (!U_SUCCESS(status))\n                {\n                    return new Range<int>(0, 0);\n                }\n            }\n\n            word_breaker_.setText(icu.UnicodeString(false, text_.data(), text_.Count));\n\n            int prev_boundary = word_breaker_.preceding(offset + 1);\n            int next_boundary = word_breaker_.next();\n            if (prev_boundary == icu.BreakIterator.DONE)\n            {\n                prev_boundary = offset;\n            }\n            if (next_boundary == icu.BreakIterator.DONE)\n            {\n                next_boundary = offset;\n            }\n            return new Range<int>(prev_boundary, next_boundary);\n        }\n\n        // Returns the number of lines the paragraph takes up. If the text exceeds the\n        // amount width and maxlines provides, Layout() truncates the extra text from\n        // the layout and this will return the max lines allowed.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int GetLineCount() const\n        public int GetLineCount()\n        {\n            return line_heights_.Count;\n        }\n\n        // Checks if the layout extends past the maximum lines and had to be\n        // truncated.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool DidExceedMaxLines() const\n        public bool DidExceedMaxLines()\n        {\n            return did_exceed_max_lines_;\n        }\n\n        // Sets the needs_layout_ to dirty. When Layout() is called, a new Layout will\n        // be performed when this is set to true. Can also be used to prevent a new\n        // Layout from being calculated by setting to false.\n        public void SetDirty(bool dirty = true)\n        {\n            needs_layout_ = dirty;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: C# has no concept of a 'friend' class:\n        //  friend class ParagraphBuilder;\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleRedParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, RainbowParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, BoldParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DecorationsParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ItalicsParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ChineseParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SpacingParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, LongWordParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, KernScaleParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, NewlineParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, EmojiParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, Ellipsize);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleShadow);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ComplexShadow);\n\n        // Starting data to layout.\n        private List<UInt16> text_ = new List<UInt16>();\n        private StyledRuns runs_ = new StyledRuns();\n        private ParagraphStyle paragraph_style_ = new ParagraphStyle();\n        private FontCollection font_collection_;\n\n        private minikin.LineBreaker breaker_ = new minikin.LineBreaker();\n        private icu.BreakIterator word_breaker_ = new icu.BreakIterator();\n\n        private class LineRange\n        {\n            public LineRange(int s, int e, int eew, int ein, bool h)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.start = s;\n                this.start = s;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.end = e;\n                this.end = e;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.end_excluding_whitespace = eew;\n                this.end_excluding_whitespace = eew;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.end_including_newline = ein;\n                this.end_including_newline = ein;\n                this.hard_break = h;\n            }\n            public int start = new int();\n            public int end = new int();\n            public int end_excluding_whitespace = new int();\n            public int end_including_newline = new int();\n            public bool hard_break;\n        }\n        private List<LineRange> line_ranges_ = new List<LineRange>();\n        private List<double> line_widths_ = new List<double>();\n\n        // Stores the result of Layout().\n        private List<PaintRecord> records_ = new List<PaintRecord>();\n\n        private List<double> line_heights_ = new List<double>();\n        private List<double> line_baselines_ = new List<double>();\n        private bool did_exceed_max_lines_;\n\n        // Metrics for use in GetRectsForRange(...);\n        // Per-line max metrics over all runs in a given line.\n        private List<float> line_max_spacings_ = new List<float>();\n        private List<float> line_max_descent_ = new List<float>();\n        private List<float> line_max_ascent_ = new List<float>();\n        // Overall left and right extremes over all lines.\n        private double max_right_;\n        private double min_left_;\n\n        internal class BidiRun\n        {\n            public BidiRun(int s, int e, TextDirection d, TextStyle st)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.start_ = s;\n                this.start_ = s;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.end_ = e;\n                this.end_ = e;\n                this.direction_ = d;\n                this.style_ = st;\n            }\n\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: int start() const\n            public int start()\n            {\n                return start_;\n            }\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: int end() const\n            public int end()\n            {\n                return end_;\n            }\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: TextDirection direction() const\n            public TextDirection direction()\n            {\n                return direction_;\n            }\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: const TextStyle& style() const\n            public TextStyle style()\n            {\n                return style_;\n            }\n            //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n            //ORIGINAL LINE: bool is_rtl() const\n            public bool is_rtl()\n            {\n                return direction_ == TextDirection.rtl;\n            }\n\n            private int start_ = new int();\n            private int end_ = new int();\n            private TextDirection direction_;\n            private readonly TextStyle style_;\n        }\n\n        internal class GlyphPosition\n        {\n            public Range<int> code_units = new Range<int>();\n            public Range<double> x_pos = new Range<double>();\n\n            public GlyphPosition(double x_start, double x_advance, int code_unit_index, int code_unit_width)\n            {\n                this.code_units = new Range<int>(code_unit_index, code_unit_index + code_unit_width);\n                this.x_pos = new Paragraph.Range<double>(x_start, x_start + x_advance);\n            }\n\n            public void Shift(double delta)\n            {\n                x_pos.Shift(delta);\n            }\n        }\n\n        internal class GlyphLine\n        {\n            // Glyph positions sorted by x coordinate.\n            public readonly List<GlyphPosition> positions = new List<GlyphPosition>();\n            public readonly int total_code_units = new int();\n\n            //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n            public GlyphLine(List<GlyphPosition> p, int tcu)\n            {\n                this.positions = p;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.total_code_units = tcu;\n                this.total_code_units = tcu;\n            }\n        }\n\n        internal class CodeUnitRun\n        {\n            // Glyph positions sorted by code unit index.\n            public List<GlyphPosition> positions = new List<GlyphPosition>();\n            public Range<int> code_units = new Range<int>();\n            public Range<double> x_pos = new Range<double>();\n            public int line_number = new int();\n            public SKFontMetrics font_metrics = new SKFontMetrics();\n            public TextDirection direction;\n\n            //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n            public CodeUnitRun(List<GlyphPosition> p, Range<int> cu, Range<double> x, int line, SKFontMetrics metrics, TextDirection dir)\n            {\n                this.positions = p;\n                this.code_units = cu;\n                this.x_pos = x;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.line_number = line;\n                this.line_number = line;\n                this.font_metrics = metrics;\n                this.direction = dir;\n            }\n\n            public void Shift(double delta)\n            {\n                x_pos.Shift(delta);\n                foreach (GlyphPosition position in positions)\n                {\n                    position.Shift(delta);\n                }\n            }\n        }\n\n        // Holds the laid out x positions of each glyph.\n        private List<GlyphLine> glyph_lines_ = new List<GlyphLine>();\n\n        // Holds the positions of each range of code units in the text.\n        // Sorted in code unit index order.\n        private List<CodeUnitRun> code_unit_runs_ = new List<CodeUnitRun>();\n\n        // The max width of the paragraph as provided in the most recent Layout()\n        // call.\n        private double width_ = -1.0f;\n        private double max_intrinsic_width_ = 0;\n        private double min_intrinsic_width_ = 0;\n        private double alphabetic_baseline_ = double.MaxValue; // FLT_MAX;\n        private double ideographic_baseline_ = double.MaxValue; // FLT_MAX;\n\n        private bool needs_layout_ = true;\n\n        private class WaveCoordinates\n        {\n            public double x_start;\n            public double y_start;\n            public double x_end;\n            public double y_end;\n\n            public WaveCoordinates(double x_s, double y_s, double x_e, double y_e)\n            {\n                this.x_start = x_s;\n                this.y_start = y_s;\n                this.x_end = x_e;\n                this.y_end = y_e;\n            }\n        }\n\n        // Passes in the text and Styled Runs. text_ and runs_ will later be passed\n        // into breaker_ in InitBreaker(), which is called in Layout().\n        private void SetText(List<UInt16> text, StyledRuns runs)\n        {\n            needs_layout_ = true;\n            if (text.Count == 0)\n            {\n                return;\n            }\n            text_ = text;\n            runs_ = runs;\n        }\n\n        private void SetParagraphStyle(ParagraphStyle style)\n        {\n            needs_layout_ = true;\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: paragraph_style_ = style;\n            paragraph_style_ = style;\n        }\n\n        private void SetFontCollection(FontCollection font_collection)\n        {\n            font_collection_ = font_collection;\n        }\n\n        // Break the text into lines.\n        private bool ComputeLineBreaks()\n        {\n            line_ranges_.Clear();\n            line_widths_.Clear();\n            max_intrinsic_width_ = 0;\n\n            List<int> newline_positions = new List<int>();\n            for (int i = 0; i < text_.Count; ++i)\n            {\n                ULineBreak ulb = (ULineBreak)u_getIntPropertyValue(text_[i], UCHAR_LINE_BREAK);\n                if (ulb == U_LB_LINE_FEED || ulb == U_LB_MANDATORY_BREAK)\n                {\n                    newline_positions.Add(i);\n                }\n            }\n            newline_positions.Add(text_.Count);\n\n            int run_index = 0;\n            for (int newline_index = 0; newline_index < newline_positions.Count; ++newline_index)\n            {\n                int block_start = (newline_index > 0) ? newline_positions[newline_index - 1] + 1 : 0;\n                int block_end = newline_positions[newline_index];\n                int block_size = block_end - block_start;\n\n                if (block_size == 0)\n                {\n                    line_ranges_.Add(new LineRange(block_start, block_end, block_end, block_end + 1, true));\n                    line_widths_.Add(0);\n                    continue;\n                }\n\n                breaker_.setLineWidths(0.0f, 0, width_);\n                breaker_.setJustified(paragraph_style_.text_align == TextAlign.justify);\n                breaker_.setStrategy(paragraph_style_.break_strategy);\n                breaker_.resize(block_size);\n                //C++ TO C# CONVERTER TODO TASK: The memory management function 'memcpy' has no equivalent in C#:\n                breaker_.buffer =  text_.GetRange(block_start, block_size);\n                breaker_.setText();\n\n                // Add the runs that include this line to the LineBreaker.\n                double block_total_width = 0;\n                while (run_index < runs_.size())\n                {\n                    StyledRuns.Run run = runs_.GetRun(run_index);\n                    if (run.start >= block_end)\n                    {\n                        break;\n                    }\n                    if (run.end < block_start)\n                    {\n                        run_index++;\n                        continue;\n                    }\n\n                    minikin.FontStyle font = new minikin.FontStyle();\n                    minikin.MinikinPaint paint = new minikin.MinikinPaint();\n                    GlobalMembers.GetFontAndMinikinPaint(run.style, font, paint);\n                    minikin.FontCollection collection = GetMinikinFontCollectionForStyle(run.style);\n                    if (collection == null)\n                    {\n                        //FML_LOG(INFO) << \"Could not find font collection for family \\\"\" << run.style.font_family << \"\\\".\";\n                        return false;\n                    }\n                    int run_start = Math.Max(run.start, block_start) - block_start;\n                    int run_end = Math.Min(run.end, block_end) - block_start;\n                    bool isRtl = (paragraph_style_.text_direction == TextDirection.rtl);\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created:\n                    //ORIGINAL LINE: double run_width = breaker_.addStyleRun(&paint, collection, font, run_start, run_end, isRtl);\n                    double run_width = breaker_.addStyleRun(paint, collection, new minikin.FontStyle(font), run_start, run_end, isRtl);\n                    block_total_width += run_width;\n\n                    if (run.end > block_end)\n                    {\n                        break;\n                    }\n                    run_index++;\n                }\n\n                max_intrinsic_width_ = Math.Max(max_intrinsic_width_, block_total_width);\n\n                int breaks_count = breaker_.computeBreaks();\n                int[] breaks = breaker_.getBreaks();\n                for (int i = 0; i < breaks_count; ++i)\n                {\n                    int break_start = (i > 0) ? breaks[i - 1] : 0;\n                    int line_start = break_start + block_start;\n                    int line_end = breaks[i] + block_start;\n                    bool hard_break = i == breaks_count - 1;\n                    int line_end_including_newline = (hard_break && line_end < text_.Count) ? line_end + 1 : line_end;\n                    int line_end_excluding_whitespace = line_end;\n                    while (line_end_excluding_whitespace > line_start && minikin.isLineEndSpace(text_[line_end_excluding_whitespace - 1]))\n                    {\n                        line_end_excluding_whitespace--;\n                    }\n                    line_ranges_.Add(new LineRange(line_start, line_end, line_end_excluding_whitespace, line_end_including_newline, hard_break));\n                    line_widths_.Add(breaker_.getWidths()[i]);\n                }\n\n                breaker_.finish();\n            }\n\n            return true;\n        }\n\n        // Break the text into runs based on LTR/RTL text direction.\n        private bool ComputeBidiRuns(List<BidiRun> result)\n        {\n            if (text_.Count == 0)\n            {\n                return true;\n            }\n\n            //C++ TO C# CONVERTER TODO TASK: Lambda expressions cannot be assigned to 'var':\n            var ubidi_closer = (UBiDi b) =>\n            {\n                ubidi_close(b);\n            };\n            var bidi = new std::unique_ptr<UBiDi, decltype(ubidi_closer) > (ubidi_open(), ubidi_closer);\n            if (bidi == null)\n            {\n                return false;\n            }\n\n            UBiDiLevel paraLevel = (paragraph_style_.text_direction == TextDirection.rtl) ? UBIDI_RTL : UBIDI_LTR;\n            UErrorCode status = U_ZERO_ERROR;\n            //C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#:\n            ubidi_setPara(bidi.get(), text_.data(), text_.Count, paraLevel, null, status);\n            if (!U_SUCCESS(status))\n            {\n                return false;\n            }\n\n            int bidi_run_count = ubidi_countRuns(bidi.get(), status);\n            if (!U_SUCCESS(status))\n            {\n                return false;\n            }\n\n            // Build a map of styled runs indexed by start position.\n            SortedDictionary<int, StyledRuns.Run> styled_run_map = new SortedDictionary<int, StyledRuns.Run>();\n            for (int i = 0; i < runs_.size(); ++i)\n            {\n                StyledRuns.Run run = runs_.GetRun(i);\n                styled_run_map.Add(run.start, run);\n            }\n\n            for (int bidi_run_index = 0; bidi_run_index < bidi_run_count; ++bidi_run_index)\n            {\n                int bidi_run_start = new int();\n                int bidi_run_length = new int();\n                UBiDiDirection direction = ubidi_getVisualRun(bidi.get(), bidi_run_index, bidi_run_start, bidi_run_length);\n                if (!U_SUCCESS(status))\n                {\n                    return false;\n                }\n\n                // Exclude the leading bidi control character if present.\n                UChar32 first_char = new UChar32();\n                U16_GET(text_.data(), 0, bidi_run_start, (int)text_.Count, first_char);\n                if (u_hasBinaryProperty(first_char, UCHAR_BIDI_CONTROL))\n                {\n                    bidi_run_start++;\n                    bidi_run_length--;\n                }\n                if (bidi_run_length == 0)\n                {\n                    continue;\n                }\n\n                // Exclude the trailing bidi control character if present.\n                UChar32 last_char = new UChar32();\n                U16_GET(text_.data(), 0, bidi_run_start + bidi_run_length - 1, (int)text_.Count, last_char);\n                if (u_hasBinaryProperty(last_char, UCHAR_BIDI_CONTROL))\n                {\n                    bidi_run_length--;\n                }\n                if (bidi_run_length == 0)\n                {\n                    continue;\n                }\n\n                int bidi_run_end = bidi_run_start + bidi_run_length;\n                TextDirection text_direction = direction == UBIDI_RTL ? TextDirection.rtl : TextDirection.ltr;\n\n                // Break this bidi run into chunks based on text style.\n                List<BidiRun> chunks = new List<BidiRun>();\n                int chunk_start = bidi_run_start;\n                while (chunk_start < bidi_run_end)\n                {\n                    var styled_run_iter = styled_run_map.upper_bound(chunk_start);\n                    styled_run_iter--;\n                    StyledRuns.Run styled_run = styled_run_iter.Value;\n                    int chunk_end = Math.Min(bidi_run_end, styled_run.end);\n                    chunks.Add(chunk_start, chunk_end, text_direction, styled_run.style);\n                    //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                    //ORIGINAL LINE: chunk_start = chunk_end;\n                    chunk_start = chunk_end;\n                }\n\n                if (text_direction == TextDirection.ltr)\n                {\n                    result.AddRange(chunks);\n                }\n                else\n                {\n                    //C++ TO C# CONVERTER TODO TASK: There is no direct equivalent to the STL vector 'insert' method in C#:\n                    result.insert(result.end(), chunks.rbegin(), chunks.rend());\n                }\n            }\n\n            return true;\n        }\n\n        // Calculate the starting X offset of a line based on the line's width and\n        // alignment.\n        private double GetLineXOffset(double line_total_advance)\n        {\n            if (double.IsInfinity(width_))\n            {\n                return 0;\n            }\n\n            TextAlign align = paragraph_style_.effective_align();\n\n            if (align == TextAlign.right)\n            {\n                return width_ - line_total_advance;\n            }\n            else if (align == TextAlign.center)\n            {\n                return (width_ - line_total_advance) / 2;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        // Creates and draws the decorations onto the canvas.\n        private void PaintDecorations(SKCanvas canvas, PaintRecord record, SKPoint base_offset)\n        {\n            if (record.style().decoration == (int)TextDecoration.kNone)\n            {\n                return;\n            }\n\n            SKFontMetrics metrics = record.metrics();\n            SKPaint paint = new SKPaint();\n            paint.setStyle(SKPaint.Style.kStroke_Style);\n            if (record.style().decoration_color == GlobalMembers.SK_ColorTRANSPARENT)\n            {\n                paint.setColor(record.style().color);\n            }\n            else\n            {\n                paint.Color = record.style().decoration_color;\n            }\n            paint.setAntiAlias(true);\n\n            // This is set to 2 for the double line style\n            int decoration_count = 1;\n\n            // Filled when drawing wavy decorations.\n            SKPath path = new SKPath();\n\n            double width = 0;\n            if (paragraph_style_.text_align == TextAlign.justify && record.line() != GetLineCount() - 1)\n            {\n                width = width_;\n            }\n            else\n            {\n                width = record.GetRunWidth();\n            }\n\n            float underline_thickness;\n            if ((metrics.fFlags & (int)SKFontMetrics.FontMetricsFlags.kUnderlineThicknessIsValid_Flag) && metrics.fUnderlineThickness > 0F)\n            {\n                underline_thickness = metrics.fUnderlineThickness;\n            }\n            else\n            {\n                // Backup value if the fUnderlineThickness metric is not available:\n                // Divide by 14pt as it is the default size.\n                underline_thickness = record.style().font_size / 14.0f;\n            }\n            paint.setStrokeWidth(underline_thickness * record.style().decoration_thickness_multiplier);\n\n            SKPoint record_offset = base_offset + record.offset();\n            float x = record_offset.X;\n            float y = record_offset.Y;\n\n            // Setup the decorations.\n            switch (record.style().decoration_style)\n            {\n                case TextDecorationStyle.kSolid:\n                    {\n                        break;\n                    }\n                case TextDecorationStyle.kDouble:\n                    {\n                        decoration_count = 2;\n                        break;\n                    }\n                // Note: the intervals are scaled by the thickness of the line, so it is\n                // possible to change spacing by changing the decoration_thickness\n                // property of TextStyle.\n                case TextDecorationStyle.kDotted:\n                    {\n                        // Divide by 14pt as it is the default size.\n                        float scale = record.style().font_size / 14.0f;\n                        float[] intervals = { 1.0f * scale, 1.5f * scale, 1.0f * scale, 1.5f * scale };\n                        //C++ TO C# CONVERTER WARNING: This 'sizeof' ratio was replaced with a direct reference to the array length:\n                        //ORIGINAL LINE: int count = sizeof(intervals) / sizeof(intervals[0]);\n                        int count = intervals.Length;\n                        paint.SetPathEffect(SKPathEffect.MakeCompose(SkDashPathEffect.Make(intervals, count, 0.0f), SkDiscretePathEffect.Make(0F, 0F)));\n                        break;\n                    }\n                // Note: the intervals are scaled by the thickness of the line, so it is\n                // possible to change spacing by changing the decoration_thickness\n                // property of TextStyle.\n                case TextDecorationStyle.kDashed:\n                    {\n                        // Divide by 14pt as it is the default size.\n                        float scale = record.style().font_size / 14.0f;\n                        float[] intervals = { 4.0f * scale, 2.0f * scale, 4.0f * scale, 2.0f * scale };\n                        //C++ TO C# CONVERTER WARNING: This 'sizeof' ratio was replaced with a direct reference to the array length:\n                        //ORIGINAL LINE: int count = sizeof(intervals) / sizeof(intervals[0]);\n                        int count = intervals.Length;\n                        paint.setPathEffect(SKPathEffect.MakeCompose(SkDashPathEffect.Make(intervals, count, 0.0f), SkDiscretePathEffect.Make(0F, 0F)));\n                        break;\n                    }\n                case TextDecorationStyle.kWavy:\n                    {\n                        int wave_count = 0;\n                        double x_start = 0;\n                        double wavelength = underline_thickness * record.style().decoration_thickness_multiplier;\n                        path.MoveTo(x, y);\n                        while (x_start + wavelength * 2 < width)\n                        {\n                            path.RQuadTo(wavelength, wave_count % 2 != 0 ? wavelength : -wavelength, wavelength * 2, 0F);\n                            x_start += wavelength * 2;\n                            ++wave_count;\n                        }\n                        break;\n                    }\n            }\n\n            // Draw the decorations.\n            // Use a for loop for \"kDouble\" decoration style\n            for (int i = 0; i < decoration_count; i++)\n            {\n                double y_offset = i * underline_thickness * GlobalMembers.kDoubleDecorationSpacing;\n                double y_offset_original = y_offset;\n                // Underline\n                if ((record.style().decoration & (int)TextDecoration.kUnderline) != 0)\n                {\n                    y_offset += ((metrics.fFlags & (int)SKFontMetrics.FontMetricsFlags.kUnderlinePositionIsValid_Flag) != null) ? metrics.fUnderlinePosition : underline_thickness;\n                    if (record.style().decoration_style != TextDecorationStyle.kWavy)\n                    {\n                        canvas.DrawLine(x, (float)(y + y_offset), (float)(x + width), (float)(y + y_offset), paint);\n                    }\n                    else\n                    {\n                        SKPath offsetPath = new SKPath(path);\n                        offsetPath.Offset(0F, (float)y_offset);\n                        canvas.DrawPath(offsetPath, paint);\n                    }\n                    y_offset = y_offset_original;\n                }\n                // Overline\n                if ((record.style().decoration & (int)TextDecoration.kOverline) != 0)\n                {\n                    // We subtract fAscent here because for double overlines, we want the\n                    // second line to be above, not below the first.\n                    y_offset -= metrics.fAscent;\n                    if (record.style().decoration_style != TextDecorationStyle.kWavy)\n                    {\n                        canvas.DrawLine(x, y - y_offset, x + width, y - y_offset, paint);\n                    }\n                    else\n                    {\n                        SKPath offsetPath = new SKPath(path);\n                        offsetPath.Offset(0F, (float)-y_offset);\n                        canvas.DrawPath(offsetPath, paint);\n                    }\n                    y_offset = y_offset_original;\n                }\n                // Strikethrough\n                if ((record.style().decoration & (int)TextDecoration.kLineThrough) != 0)\n                {\n                    if (metrics.fFlags & (int)SKFontMetrics.FontMetricsFlags.kStrikeoutThicknessIsValid_Flag != null)\n                    {\n                        paint.setStrokeWidth(metrics.fStrikeoutThickness * record.style().decoration_thickness_multiplier);\n                    }\n                    // Make sure the double line is \"centered\" vertically.\n                    y_offset += (decoration_count - 1.0) * underline_thickness * GlobalMembers.kDoubleDecorationSpacing / -2.0;\n                    y_offset += ((metrics.fFlags & (int)SKFontMetrics.FontMetricsFlags.kStrikeoutThicknessIsValid_Flag) != null) ? metrics.fStrikeoutPosition : metrics.fXHeight / -2.0;\n                    if (record.style().decoration_style != TextDecorationStyle.kWavy)\n                    {\n                        canvas.DrawLine(x, y + y_offset, x + width, y + y_offset, paint);\n                    }\n                    else\n                    {\n                        SKPath offsetPath = new SKPath(path);\n                        offsetPath.Offset(0F, (float)y_offset);\n                        canvas.DrawPath(offsetPath, paint);\n                    }\n                    y_offset = y_offset_original;\n                }\n            }\n        }\n\n        // Draws the background onto the canvas.\n        private void PaintBackground(SKCanvas canvas, PaintRecord record, SKPoint base_offset)\n        {\n            if (!record.style().has_background)\n            {\n                return;\n            }\n\n            SKFontMetrics metrics = record.metrics();\n            SKRect rect = new SKRect(0, metrics.fAscent, record.GetRunWidth(), metrics.fDescent);\n            rect.Offset(base_offset + record.offset());\n            canvas.DrawRect(rect, record.style().background);\n        }\n\n        // Draws the shadows onto the canvas.\n        private void PaintShadow(SKCanvas canvas, PaintRecord record, SKPoint offset)\n        {\n            if (record.style().text_shadows.Count == 0)\n            {\n                return;\n            }\n            foreach (TextShadow text_shadow in record.style().text_shadows)\n            {\n                if (!text_shadow.hasShadow())\n                {\n                    continue;\n                }\n\n                SKPaint paint = new SKPaint();\n                paint.Color = text_shadow.color;\n                if (text_shadow.blur_radius != 0.0)\n                {\n                    paint.setMaskFilter(SkMaskFilter.MakeBlur(SkBlurStyle.kNormal_SkBlurStyle, text_shadow.blur_radius, false));\n                }\n                canvas.DrawText(record.text(), offset.X + text_shadow.offset.X, offset.Y + text_shadow.offset.Y, paint);\n            }\n        }\n\n        // Obtain a Minikin font collection matching this text style.\n        private minikin.FontCollection GetMinikinFontCollectionForStyle(TextStyle style)\n        {\n            string locale;\n            if (!string.IsNullOrEmpty(style.locale))\n            {\n                uint language_list_id = minikin.FontStyle.registerLanguageList(style.locale);\n                minikin.FontLanguages langs = minikin.FontLanguageListCache.getById(language_list_id);\n                if (langs != null)\n                {\n                    locale = langs[0].getString();\n                }\n            }\n\n            return font_collection_.GetMinikinFontCollectionForFamily(style.font_family, locale);\n        }\n\n        // Get a default SkTypeface for a text style.\n        private SKTypeface GetDefaultSkiaTypeface(TextStyle style)\n        {\n            minikin.FontCollection collection = GetMinikinFontCollectionForStyle(style);\n            if (collection == null)\n            {\n                return null;\n            }\n            minikin.FakedFont faked_font = collection.baseFontFaked(GlobalMembers.GetMinikinFontStyle(style));\n            return ((FontSkia)faked_font.font).GetSkTypeface();\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FML_DISALLOW_COPY_AND_ASSIGN(Paragraph);\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/ubidi.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"unicode/utf16.h\"\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAutoCanvasRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoCanvasRestore)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REGISTER_FLATTENABLE(type) SkFlattenable::Register(#type, type::CreateProc);\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLATTENABLE_HOOKS(type) static sk_sp<SkFlattenable> CreateProc(SkReadBuffer&); friend class SkFlattenable::PrivateInitializer; Factory getFactory() const override { return type::CreateProc; } const char* getTypeName() const override { return #type; }\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkTypeface.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name;\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAutoExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoExclusive)\n\nnamespace FlutterBinding.Txt\n{\n    //C++ TO C# CONVERTER NOTE: C# does not allow anonymous namespaces:\n    //namespace\n\n    //public class GlyphTypeface\n    //{\n    //    public GlyphTypeface(SKTypeface typeface, minikin.FontFakery fakery)\n    //    {\n    //        this.typeface_ = typeface;\n    //        this.fake_bold_ = fakery.isFakeBold();\n    //        this.fake_italic_ = fakery.isFakeItalic();\n    //    }\n\n    //    //public static bool operator ==(GlyphTypeface ImpliedObject, GlyphTypeface other)\n    //    //{\n    //    //    return other.typeface_.get() == ImpliedObject.typeface_.get() && other.fake_bold_ == ImpliedObject.fake_bold_ && other.fake_italic_ == ImpliedObject.fake_italic_;\n    //    //}\n\n    //    //public static bool operator !=(GlyphTypeface ImpliedObject, GlyphTypeface other)\n    //    //{\n    //    //    return !(*ImpliedObject == other);\n    //    //}\n\n    //    public void apply(SKPaint paint)\n    //    {\n    //        paint.setTypeface(new SKTypeface(typeface_));\n    //        paint.setFakeBoldText(fake_bold_);\n    //        paint.setTextSkewX(fake_italic_ ? -DefineConstants.SK_Scalar1 / 4 : 0F);\n    //    }\n\n    //    private SKTypeface typeface_;\n    //    private bool fake_bold_;\n    //    private bool fake_italic_;\n    //}\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/paragraph_builder.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/macros.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WHEN(condition, T) skstd::enable_if_t<!!(condition), T>\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkStrAppendScalar SkStrAppendFloat\n\nnamespace FlutterBinding.Txt\n{\n\n    public class ParagraphBuilder //: System.IDisposable\n    {\n        public ParagraphBuilder(ParagraphStyle style, FontCollection font_collection)\n        {\n            this.font_collection_ = font_collection;\n            SetParagraphStyle(style);\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        // Push a style to the stack. The corresponding text added with AddText will\n        // use the top-most style.\n        public void PushStyle(TextStyle style)\n        {\n            int style_index = runs_.AddStyle(style);\n            style_stack_.Add(style_index);\n            runs_.StartRun(style_index, text_.Count);\n        }\n\n        // Remove a style from the stack. Useful to apply different styles to chunks\n        // of text such as bolding.\n        // Example:\n        //   builder.PushStyle(normal_style);\n        //   builder.AddText(\"Hello this is normal. \");\n        //\n        //   builder.PushStyle(bold_style);\n        //   builder.AddText(\"And this is BOLD. \");\n        //\n        //   builder.Pop();\n        //   builder.AddText(\" Back to normal again.\");\n        public void Pop()\n        {\n            if (style_stack_.Count == 0)\n            {\n                return;\n            }\n            style_stack_.RemoveAt(style_stack_.Count - 1);\n            runs_.StartRun(PeekStyleIndex(), text_.Count);\n        }\n\n        // Returns the last TextStyle on the stack.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const TextStyle& PeekStyle() const\n        public TextStyle PeekStyle()\n        {\n            return runs_.GetStyle(PeekStyleIndex());\n        }\n\n        // Adds text to the builder. Forms the proper runs to use the upper-most style\n        // on the style_stack_;\n        public void AddText(std::u16string text)\n        {\n            text_.AddRange(text);\n        }\n\n        // Converts to u16string before adding.\n        public void AddText(string text)\n        {\n            var icu_text = icu.UnicodeString.fromUTF8(text);\n            std::u16string u16_text = new std::u16string(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length());\n            AddText(u16_text);\n        }\n\n        // Converts to u16string before adding.\n        public void AddText(string text)\n        {\n            var icu_text = icu.UnicodeString.fromUTF8(text);\n            std::u16string u16_text = new std::u16string(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length());\n            AddText(u16_text);\n        }\n\n        public void SetParagraphStyle(ParagraphStyle style)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: paragraph_style_ = style;\n            paragraph_style_.CopyFrom(style);\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: paragraph_style_index_ = runs_.AddStyle(style.GetTextStyle());\n            paragraph_style_index_.CopyFrom(runs_.AddStyle(style.GetTextStyle()));\n            runs_.StartRun(paragraph_style_index_, text_.Count);\n        }\n\n        // Constructs a Paragraph object that can be used to layout and paint the text\n        // to a SKCanvas.\n        public Paragraph Build()\n        {\n            runs_.EndRunIfNeeded(text_.Count);\n\n            Paragraph paragraph = new Paragraph();\n            paragraph.SetText(text_, runs_);\n            paragraph.SetParagraphStyle(paragraph_style_);\n            paragraph.SetFontCollection(font_collection_);\n            return paragraph;\n        }\n\n        private List<UInt16> text_ = new List<UInt16>();\n        private List<int> style_stack_ = new List<int>();\n        private FontCollection font_collection_;\n        private StyledRuns runs_ = new StyledRuns();\n        private ParagraphStyle paragraph_style_ = new ParagraphStyle();\n        private int paragraph_style_index_ = new int();\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int PeekStyleIndex() const\n        private int PeekStyleIndex()\n        {\n            return style_stack_.Count ? style_stack_[style_stack_.Count - 1] : paragraph_style_index_;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FML_DISALLOW_COPY_AND_ASSIGN(ParagraphBuilder);\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/icu/source/common/unicode/unistr.h\"\n\nnamespace FlutterBinding.Txt\n{\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //ParagraphBuilder::~ParagraphBuilder() = default;\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/paragraph_style.cs",
    "content": "﻿/*\n * Copyright 2017 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n\nnamespace FlutterBinding.Txt\n{\n\n    public enum TextAlign\n    {\n        left,\n        right,\n        center,\n        justify,\n        start,\n        end,\n    }\n\n    public enum TextDirection\n    {\n        rtl,\n        ltr,\n    }\n\n    public class ParagraphStyle\n    {\n        public FontWeight font_weight = FontWeight.w400;\n        public FontStyle font_style = FontStyle.normal;\n        public string font_family = \"\";\n        public double font_size = 14;\n\n        public TextAlign text_align = TextAlign.start;\n        public TextDirection text_direction = TextDirection.ltr;\n        public int max_lines = int.MaxValue;\n        public double line_height = 1.0;\n        public std::u16string ellipsis = new std::u16string();\n        public string locale;\n\n        // Default strategy is kBreakStrategy_Greedy. Sometimes,\n        // kBreakStrategy_HighQuality will produce more desireable layouts (eg, very\n        // long words are more likely to be reasonably placed).\n        // kBreakStrategy_Balanced will balance between the two.\n        public minikin.BreakStrategy break_strategy = minikin.BreakStrategy.kBreakStrategy_Greedy;\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: TextStyle GetTextStyle() const\n        public TextStyle GetTextStyle()\n        {\n            TextStyle result = new TextStyle();\n            result.font_weight = font_weight;\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: result.font_style = font_style;\n            result.font_style.CopyFrom(font_style);\n            result.font_family = font_family;\n            result.font_size = font_size;\n            result.locale = locale;\n            result.height = line_height;\n            return result;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool unlimited_lines() const\n        public bool unlimited_lines()\n        {\n            return max_lines == int.MaxValue;\n        }\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool ellipsized() const\n        public bool ellipsized()\n        {\n            return !ellipsis.empty();\n        }\n\n        // Return a text alignment value that is not dependent on the text direction.\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: TextAlign effective_align() const\n        public TextAlign effective_align()\n        {\n            if (text_align == TextAlign.start)\n            {\n                return (text_direction == TextDirection.ltr) ? TextAlign.left : TextAlign.right;\n            }\n            else if (text_align == TextAlign.end)\n            {\n                return (text_direction == TextDirection.ltr) ? TextAlign.right : TextAlign.left;\n            }\n            else\n            {\n                return text_align;\n            }\n        }\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Txt/platform.cs",
    "content": "﻿// Copyright 2017 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// Copyright 2017 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\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/macros.h\"\n\n\n\n\n"
  },
  {
    "path": "FlutterBinding/Txt/platform_android.cs",
    "content": "﻿// Copyright 2017 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\n"
  },
  {
    "path": "FlutterBinding/Txt/styled_runs.cs",
    "content": "﻿using System.Collections.Generic;\n\n/*\n * Copyright (C) 2017 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/googletest/googletest/include/gtest/gtest_prod.h\" // nogncheck\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) FRIEND_TEST(SUITE, TEST_NAME)\n\nnamespace FlutterBinding.Txt\n{\n\n    // This holds and handles the start/end positions of discrete chunks of text\n    // that use different styles (a 'run').\n    public class StyledRuns //: System.IDisposable\n    {\n        public class Run\n        {\n            public TextStyle style;\n            public int start;\n            public int end;\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  StyledRuns();\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = delete':\n        //  StyledRuns(const StyledRuns& other) = delete;\n\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        public StyledRuns(StyledRuns other)\n        {\n            styles_.Swap(other.styles_);\n            runs_.Swap(other.runs_);\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: 'rvalue references' have no equivalent in C#:\n        //C++ TO C# CONVERTER TODO TASK: The = operator cannot be overloaded in C#:\n        //public static StyledRuns operator = (StyledRuns && other)\n        //{\n        //    styles_.Swap(other.styles_);\n        //    runs_.Swap(other.runs_);\n        //    return this;\n        //}\n\n        public void swap(StyledRuns other)\n        {\n            styles_.Swap(other.styles_);\n            runs_.Swap(other.runs_);\n        }\n\n        public int AddStyle(TextStyle style)\n        {\n            int style_index = styles_.Count;\n            styles_.Add(style);\n            return style_index;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: const TextStyle& GetStyle(int style_index) const\n        public TextStyle GetStyle(int style_index)\n        {\n            return styles_[style_index];\n        }\n\n        public void StartRun(int style_index, int start)\n        {\n            EndRunIfNeeded(start);\n            runs_.Add(new IndexedRun(style_index, start, start));\n        }\n\n        public void EndRunIfNeeded(int end)\n        {\n            if (runs_.Count == 0)\n            {\n                return;\n            }\n            IndexedRun run = runs_[runs_.Count - 1];\n            if (run.start == end)\n            {\n                // The run is empty. We can skip it.\n                runs_.RemoveAt(runs_.Count - 1);\n            }\n            else\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: run.end = end;\n                run.end = end;\n            }\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int size() const\n        public int size()\n        {\n            return runs_.Count;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: StyledRuns::Run GetRun(int index) const\n        public StyledRuns.Run GetRun(int index)\n        {\n            IndexedRun run = runs_[index];\n            return new Run() { style = styles_[run.style_index], start = run.start, end = run.end };\n        }\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleRedParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, RainbowParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, BoldParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DecorationsParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ItalicsParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ChineseParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, DISABLED_ArabicParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, LongWordParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, KernParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, Ellipsize);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, SimpleShadow);\n        ////C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FRIEND_TEST(ParagraphTest, ComplexShadow);\n\n        private class IndexedRun\n        {\n            public int style_index = 0;\n            public int start = 0;\n            public int end = 0;\n\n            public IndexedRun(int style_index, int start, int end)\n            {\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.style_index = style_index;\n                this.style_index = style_index;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.start = start;\n                this.start = start;\n                //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n                //ORIGINAL LINE: this.end = end;\n                this.end = end;\n            }\n        }\n\n        private List<TextStyle> styles_ = new List<TextStyle>();\n        private List<IndexedRun> runs_ = new List<IndexedRun>();\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n\nnamespace FlutterBinding.Txt\n{\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //StyledRuns::StyledRuns() = default;\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //StyledRuns::~StyledRuns() = default;\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/text_baseline.cs",
    "content": "﻿/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nnamespace FlutterBinding.Txt\n{\n\npublic enum TextBaseline\n{\n  kAlphabetic,\n  kIdeographic,\n}\n\n} // namespace FlutterBinding.Txt\n\n"
  },
  {
    "path": "FlutterBinding/Txt/text_decoration.cs",
    "content": "﻿/*\n * Copyright 2017 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/*\n * Copyright 2017 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nnamespace FlutterBinding.Txt\n{\n\n// Multiple decorations can be applied at once. Ex: Underline and overline is\n// (0x1 | 0x2)\npublic enum TextDecoration\n{\n  kNone = 0x0,\n  kUnderline = 0x1,\n  kOverline = 0x2,\n  kLineThrough = 0x4,\n}\n\npublic enum TextDecorationStyle\n{\n\tkSolid,\n\tkDouble,\n\tkDotted,\n\tkDashed,\n\tkWavy\n}\n\n} // namespace FlutterBinding.Txt\n\n\n\nnamespace FlutterBinding.Txt\n{\n\n//\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/Txt/text_shadow.cs",
    "content": "﻿/*\n * Copyright 2018 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2018 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkColor.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SKPoint.h\"\n\nusing SkiaSharp;\n\nnamespace FlutterBinding.Txt\n{\n\n    public class TextShadow\n    {\n        public SKColor color = SKColor.Parse(\"#000\");// SK_ColorBLACK;\n        public SKPoint offset = new SKPoint();\n        public double blur_radius = 0.0;\n\n        public TextShadow()\n        {\n        }\n\n        public TextShadow(SKColor color, SKPoint offset, double blur_radius)\n        {\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.color = color;\n            this.color = color;\n            //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created:\n            //ORIGINAL LINE: this.offset = offset;\n            this.offset = offset;\n            this.blur_radius = blur_radius;\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool operator ==(const TextShadow& other) const\n        //public static bool operator ==(TextShadow ImpliedObject, TextShadow other)\n        //{\n        //    if (ImpliedObject.color != other.color)\n        //    {\n        //        return false;\n        //    }\n        //    if (ImpliedObject.offset != other.offset)\n        //    {\n        //        return false;\n        //    }\n        //    if (ImpliedObject.blur_radius != other.blur_radius)\n        //    {\n        //        return false;\n        //    }\n\n        //    return true;\n        //}\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool operator !=(const TextShadow& other) const\n        //public static bool operator !=(TextShadow ImpliedObject, TextShadow other)\n        //{\n        //    return !(*ImpliedObject == other);\n        //}\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool hasShadow() const\n        public bool hasShadow()\n        {\n            if (!offset.IsEmpty)\n            {\n                return true;\n            }\n            if (blur_radius != 0.0)\n            {\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkColor.h\"\n\n"
  },
  {
    "path": "FlutterBinding/Txt/text_style.cs",
    "content": "﻿using SkiaSharp;\nusing System.Collections.Generic;\n\n/*\n * Copyright 2017 Google, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkColor.h\"\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG1(arg1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG2(arg1, arg2)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NOTHING_ARG3(arg1, arg2, arg3)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_RESTRICT __restrict__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllexport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_API __declspec(dllimport)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HAS_COMPILER_FEATURE(x) 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ATTRIBUTE(attr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkNO_RETURN_HINT() do {} while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_GOOGLE3_STACK()\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s(%d): fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_DUMP_LINE_FORMAT(message) SkDebugf(\"%s:%d: fatal error: \\\"%s\\\"\\n\", __FILE__, __LINE__, message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ABORT(message) do { SkNO_RETURN_HINT(); SK_DUMP_LINE_FORMAT(message); SK_DUMP_GOOGLE3_STACK(); sk_abort_no_print(); } while (false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C3 ## 32_SHIFT == 0 && SK_ ## C2 ## 32_SHIFT == 8 && SK_ ## C1 ## 32_SHIFT == 16 && SK_ ## C0 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) (SK_ ## C0 ## 32_SHIFT == 0 && SK_ ## C1 ## 32_SHIFT == 8 && SK_ ## C2 ## 32_SHIFT == 16 && SK_ ## C3 ## 32_SHIFT == 24)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED __pragma(warning(suppress:4189))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_UNUSED SK_ATTRIBUTE(unused)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE __forceinline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE __declspec(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast<const char*>(ptr), _MM_HINT_T0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr) __builtin_prefetch(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_WRITE_PREFETCH(ptr)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_PRINTF_LIKE(A, B)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_GAMMA_EXPONENT (0.0f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_BOOLEAN(name, value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT_RELEASE(cond) static_cast<void>( (cond) ? (void)0 : []{ SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) SkASSERT_RELEASE(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>( (cond) ? (void)0 : [&]{ SkDebugf(fmt\"\\n\", __VA_ARGS__); SK_ABORT(\"assert(\" #cond \")\"); }() )\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message) SK_ABORT(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...) __VA_ARGS__\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...) SkDebugf(__VA_ARGS__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) SkASSERT(cond)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERT(cond) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAIL(message)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGFAILF(fmt, ...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGCODE(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDEBUGF(...)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkAssertResult(cond) if (cond) {} do {} while(false)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array)))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_REQUIRE_LOCAL_VAR(classname) static_assert(false, \"missing name for \" #classname)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_BEGIN_REQUIRE_DENSE _Pragma(\"GCC diagnostic push\") _Pragma(\"GCC diagnostic error \\\"-Wpadded\\\"\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_END_REQUIRE_DENSE _Pragma(\"GCC diagnostic pop\")\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_INIT_TO_AVOID_WARNING = 0\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define __inline static __inline\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sqrt(x) sqrtf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_sin(x) sinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_cos(x) cosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_tan(x) tanf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor(x) floorf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil(x) ceilf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_trunc(x) truncf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) static_cast<float>(acos(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) static_cast<float>(asin(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_acos(x) acosf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_asin(x) asinf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_atan2(y,x) atan2f(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_abs(x) fabsf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_copysign(x, y) copysignf(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_mod(x,y) fmodf(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_exp(x) expf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log(x) logf(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_log2(x) log2f(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_isnan(a) sk_float_isnan(a)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor(x) floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round(x) floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil(x) ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_floor2int(x) (int)floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_round2int(x) (int)floor((x) + 0.5)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define sk_double_ceil2int(x) (int)ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNaN NAN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatInfinity (+INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FloatNegativeInfinity (-INFINITY)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMax 3.402823466e+38f\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarInfinity SK_FloatInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNaN SK_FloatNaN\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToScalar(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToScalar(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToScalar(x) sk_float_trunc(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAbs(x) sk_float_abs(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCopySign(x, y) sk_float_copysign(x, y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarMod(x, y) sk_float_mod(x,y)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSqrt(x) sk_float_sqrt(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarPow(b, e) sk_float_pow(b, e)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarSin(radians) (float)sk_float_sin(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarCos(radians) (float)sk_float_cos(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTan(radians) (float)sk_float_tan(radians)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarASin(val) (float)sk_float_asin(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarACos(val) (float)sk_float_acos(val)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarExp(x) (float)sk_float_exp(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog(x) (float)sk_float_log(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarLog2(x) (float)sk_float_log2(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarTruncToInt(x) sk_float_saturate2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToFloat(x) static_cast<float>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkFloatToScalar(x) static_cast<SkScalar>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToDouble(x) static_cast<double>(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDoubleToScalar(x) sk_double_to_float(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarMin (-SK_ScalarMax)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarDiv(numer, denom) sk_ieee_float_divide(numer, denom)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarFastInvert(x) sk_ieee_float_divide(SK_Scalar1, (x))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarHalf(a) ((a) * SK_ScalarHalf)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_double_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_double_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_double_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_double_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_double_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_double_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloor(x) sk_float_floor(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeil(x) sk_float_ceil(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRound(x) sk_float_round(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarFloorToInt(x) sk_float_floor2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarCeilToInt(x) sk_float_ceil2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarRoundToInt(x) sk_float_round2int(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkIntToMScalar(n) static_cast<SkMScalar>(n)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkMScalarToScalar(x) SkMScalarToFloat(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkScalarToMScalar(x) SkFloatToMScalar(x)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetA(color) (((color) >> 24) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetR(color) (((color) >> 16) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetG(color) (((color) >> 8) & 0xFF)\n//C++ TO C# CONVERTER NOTE: The following #define macro was replaced in-line:\n//ORIGINAL LINE: #define SkColorGetB(color) (((color) >> 0) & 0xFF)\n\nnamespace FlutterBinding.Txt\n{\n\n    public class TextStyle\n    {\n        public uint color = SK_ColorWHITE;\n        public int decoration = (int)TextDecoration.kNone;\n        // Does not make sense to draw a transparent object, so we use it as a default\n        // value to indicate no decoration color was set.\n        public uint decoration_color = SK_ColorTRANSPARENT;\n        public TextDecorationStyle decoration_style = TextDecorationStyle.kSolid;\n        // Thickness is applied as a multiplier to the default thickness of the font.\n        public double decoration_thickness_multiplier = 1.0;\n        public FontWeight font_weight = FontWeight.w400;\n        public FontStyle font_style = FontStyle.normal;\n        public TextBaseline text_baseline = TextBaseline.kAlphabetic;\n        public string font_family;\n        public double font_size = 14.0;\n        public double letter_spacing = 0.0;\n        public double word_spacing = 0.0;\n        public double height = 1.0;\n        public string locale;\n        public bool has_background = false;\n        public SKPaint background = new SKPaint();\n        public bool has_foreground = false;\n        public SKPaint foreground = new SKPaint();\n        public List<TextShadow> text_shadows = new List<TextShadow>();\n\n        public TextStyle()\n        {\n            this.font_family = GetDefaultFontFamily();\n        }\n\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: bool equals(const TextStyle& other) const\n        public bool equals(TextStyle other)\n        {\n            if (color != other.color)\n            {\n                return false;\n            }\n            if (decoration != other.decoration)\n            {\n                return false;\n            }\n            if (decoration_color != other.decoration_color)\n            {\n                return false;\n            }\n            if (decoration_style != other.decoration_style)\n            {\n                return false;\n            }\n            if (decoration_thickness_multiplier != other.decoration_thickness_multiplier)\n            {\n                return false;\n            }\n            if (font_weight != other.font_weight)\n            {\n                return false;\n            }\n            if (font_style != other.font_style)\n            {\n                return false;\n            }\n            if (font_family != other.font_family)\n            {\n                return false;\n            }\n            if (letter_spacing != other.letter_spacing)\n            {\n                return false;\n            }\n            if (word_spacing != other.word_spacing)\n            {\n                return false;\n            }\n            if (height != other.height)\n            {\n                return false;\n            }\n            if (locale != other.locale)\n            {\n                return false;\n            }\n            if (foreground != other.foreground)\n            {\n                return false;\n            }\n            if (text_shadows.Count != other.text_shadows.Count)\n            {\n                return false;\n            }\n            for (int shadow_index = 0; shadow_index < text_shadows.Count; ++shadow_index)\n            {\n                if (text_shadows[shadow_index] != other.text_shadows[shadow_index])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkColor.h\"\n\n"
  },
  {
    "path": "FlutterBinding/Txt/typeface_font_asset_provider.cs",
    "content": "﻿using SkiaSharp;\nusing System.Collections.Generic;\n\n/*\n * Copyright 2018 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright 2018 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/macros.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkFontMgr.h\"\n\nnamespace FlutterBinding.Txt\n{\n\n    public class TypefaceFontStyleSet : SkFontStyleSet, System.IDisposable\n    {\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  TypefaceFontStyleSet();\n\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        public void registerTypeface(SKTypeface typeface)\n        {\n            if (typeface == null)\n            {\n                return;\n            }\n            typefaces_.Add(typeface);\n        }\n\n        // |SkFontStyleSet|\n        public override int count()\n        {\n            return typefaces_.Count;\n        }\n\n        // |SkFontStyleSet|\n        public override void getStyle(int index, SkFontStyle UnnamedParameter, SkString style)\n        {\n            FML_DCHECK(false);\n        }\n\n        // |SkFontStyleSet|\n        public override SkTypeface createTypeface(int i)\n        {\n            int index = i;\n            if (index >= typefaces_.Count)\n            {\n                return null;\n            }\n            return SkRef(typefaces_[index].get());\n        }\n\n        // |SkFontStyleSet|\n        public override SKTypeface matchStyle(SKFontStyle pattern)\n        {\n            if (typefaces_.Count == 0)\n            {\n                return null;\n            }\n\n            foreach (SKTypeface typeface in typefaces_)\n            {\n                if (typeface.fontStyle() == pattern)\n                {\n                    return SkRef(typeface.get());\n                }\n            }\n\n            return SkRef(typefaces_[0].get());\n        }\n\n        private List<SKTypeface> typefaces_ = new List<SKTypeface>();\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        FML_DISALLOW_COPY_AND_ASSIGN(TypefaceFontStyleSet);\n    }\n\n    public class TypefaceFontAssetProvider : FontAssetProvider\n    {\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  TypefaceFontAssetProvider();\n        //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found:\n        //  public void Dispose();\n\n        public void RegisterTypeface(SKTypeface typeface)\n        {\n            if (typeface == null)\n            {\n                return;\n            }\n\n            SkString sk_family_name = new SKString();\n            typeface.getFamilyName(sk_family_name);\n\n            string family_name = new string(sk_family_name.c_str(), sk_family_name.size());\n            RegisterTypeface(typeface, family_name);\n        }\n\n        public void RegisterTypeface(SKTypeface typeface, string family_name_alias)\n        {\n            if (string.IsNullOrEmpty(family_name_alias))\n            {\n                return;\n            }\n\n            string canonical_name = CanonicalFamilyName(family_name_alias);\n            var family_it = registered_families_.find(canonical_name);\n            if (family_it == registered_families_.end())\n            {\n                family_names_.Add(family_name_alias);\n                family_it = registered_families_.emplace(std::piecewise_construct, std::forward_as_tuple(canonical_name), std::forward_as_tuple()).first;\n            }\n            //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n            family_it.second.registerTypeface(typeface);\n        }\n\n        // |FontAssetProvider|\n\n        // |FontAssetProvider|\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: int GetFamilyCount() const override\n        public override int GetFamilyCount()\n        {\n            return family_names_.Count;\n        }\n\n        // |FontAssetProvider|\n\n        // |FontAssetProvider|\n        //C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#:\n        //ORIGINAL LINE: string GetFamilyName(int index) const override\n        public override string GetFamilyName(int index)\n        {\n            return family_names_[index];\n        }\n\n        // |FontAssetProvider|\n\n        // |FontAssetProvider|\n        public override SkFontStyleSet MatchFamily(string family_name)\n        {\n            var found = registered_families_.find(CanonicalFamilyName(family_name));\n            if (found == registered_families_.end())\n            {\n                return null;\n            }\n            //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops:\n            return SkRef(found.second);\n        }\n\n        private Dictionary<string, TypefaceFontStyleSet> registered_families_ = new Dictionary<string, TypefaceFontStyleSet>();\n        private List<string> family_names_ = new List<string>();\n\n        //C++ TO C# CONVERTER TODO TASK: The following statement was not recognized, possibly due to an unrecognized macro:\n        //FML_DISALLOW_COPY_AND_ASSIGN(TypefaceFontAssetProvider);\n    }\n\n} // namespace FlutterBinding.Txt\n\n\n\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"flutter/fml/logging.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkString.h\"\n//C++ TO C# CONVERTER WARNING: The following #include directive was ignored:\n//#include \"third_party/skia/include/core/SkTypeface.h\"\n\nnamespace FlutterBinding.Txt\n{\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //TypefaceFontAssetProvider::TypefaceFontAssetProvider() = default;\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //TypefaceFontAssetProvider::~TypefaceFontAssetProvider() = default;\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //TypefaceFontStyleSet::TypefaceFontStyleSet() = default;\n\n    //C++ TO C# CONVERTER TODO TASK: C# has no equivalent to ' = default':\n    //TypefaceFontStyleSet::~TypefaceFontStyleSet() = default;\n\n} // namespace FlutterBinding.Txt\n"
  },
  {
    "path": "FlutterBinding/UI/Compositing.cs",
    "content": "﻿using FlutterBinding.Engine.Compositing;\nusing FlutterBinding.Engine.Painting;\nusing FlutterBinding.Flow.Layers;\nusing FlutterBinding.Mapping;\nusing SkiaSharp;\nusing System;\nusing System.Collections.Generic;\nusing static FlutterBinding.Mapping.Helper;\n\nnamespace FlutterBinding.UI\n{\n\n    /// An opaque object representing a composited scene.\n    ///\n    /// To create a Scene object, use a [SceneBuilder].\n    ///\n    /// Scene objects can be displayed on the screen using the\n    /// [Window.render] method.\n    public class Scene : NativeScene\n    {\n\n        // Not sure if this should be here and public to the FlutterBinding Library\n        public Scene(Layer rootLayer,\n             uint rasterizerTracingThreshold,\n             bool checkerboardRasterCacheImages,\n             bool checkerboardOffscreenLayers) : base(rootLayer, rasterizerTracingThreshold, checkerboardRasterCacheImages, checkerboardOffscreenLayers)\n        { }\n\n        /// Creates a raster image representation of the current state of the scene.\n        /// This is a slow operation that is performed on a background thread.\n        public Future<SKImage> toImage(int width, int height)\n        {\n            if (width <= 0 || height <= 0)\n                throw new Exception(\"Invalid image dimensions.\");\n            return _futurize(\n              (_Callback<SKImage> callback) => _toImage(width, height, callback)\n            );\n        }\n\n        String _toImage(int width, int height, _Callback<SKImage> callback)\n        {\n            // create image and send via callback\n            // only send string if an error occurs.\n            return this.ToImage(width, height, callback);\n            // [DONE] native 'Scene_toImage';\n        }\n\n        /// Releases the resources used by this scene.\n        ///\n        /// After calling this function, the scene is cannot be used further.\n        public void dispose()\n        {\n            // native 'Scene_dispose';\n        }\n    }\n\n    /// Builds a [Scene] containing the given visuals.\n    ///\n    /// A [Scene] can then be rendered using [Window.render].\n    ///\n    /// To draw graphical operations onto a [Scene], first create a\n    /// [Picture] using a [PictureRecorder] and a [Canvas], and then add\n    /// it to the scene using [addPicture].\n    public class SceneBuilder : NativeSceneBuilder\n    {\n        /// Creates an empty [SceneBuilder] object.\n        public SceneBuilder() { _constructor(); }\n        void _constructor()\n        {\n            this.Constructor();\n            // [DONE] native 'SceneBuilder_constructor';\n        }\n\n        /// Pushes a transform operation onto the operation stack.\n        ///\n        /// The objects are transformed by the given matrix before rasterization.\n        ///\n        /// See [pop] for details about the operation stack.\n        public void pushTransform(List<double> matrix4)\n        {\n            if (matrix4 == null)\n                throw new ArgumentException(\"'matrix4' argument cannot be null\");\n            if (matrix4.Count != 16)\n                throw new ArgumentException(\"'matrix4' must have 16 entries.\");\n            _pushTransform(matrix4);\n        }\n        void _pushTransform(List<double> matrix4)\n        {\n            this.PushTransform(matrix4);\n            // [DONE] native 'SceneBuilder_pushTransform';\n        }\n\n        /// Pushes an offset operation onto the operation stack.\n        ///\n        /// This is equivalent to [pushTransform] with a matrix with only translation.\n        ///\n        /// See [pop] for details about the operation stack.\n        public NativeEngineLayer pushOffset(double dx, double dy)\n        {\n            return this.PushOffset(dx, dy);\n            // [DONE] native 'SceneBuilder_pushOffset';\n        }\n\n        /// Pushes a rectangular clip operation onto the operation stack.\n        ///\n        /// Rasterization outside the given rectangle is discarded.\n        ///\n        /// See [pop] for details about the operation stack, and [Clip] for different clip modes.\n        /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).\n        public void pushClipRect(Rect rect, Clip clipBehavior = Clip.antiAlias)\n        {\n            //assert(clipBehavior != null);\n            //assert(clipBehavior != Clip.none);\n            _pushClipRect(rect.left, rect.right, rect.top, rect.bottom, (int)clipBehavior);\n        }\n\n        void _pushClipRect(double left,\n                           double right,\n                           double top,\n                           double bottom,\n                           int clipBehavior)\n        {\n            this.PushClipRect(left, right, top, bottom, clipBehavior);\n            // [DONE] native 'SceneBuilder_pushClipRect';\n        }\n\n        /// Pushes a rounded-rectangular clip operation onto the operation stack.\n        ///\n        /// Rasterization outside the given rounded rectangle is discarded.\n        ///\n        /// See [pop] for details about the operation stack, and [Clip] for different clip modes.\n        /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).\n        public void pushClipRRect(RRect rrect, Clip clipBehavior = Clip.antiAlias)\n        {\n            //assert(clipBehavior != null);\n            //assert(clipBehavior != Clip.none);\n            _pushClipRRect(rrect._value, (int)clipBehavior);\n        }\n        void _pushClipRRect(List<double> rrect, int clipBehavior)\n        {\n            // native 'SceneBuilder_pushClipRRect';\n        }\n\n        /// Pushes a path clip operation onto the operation stack.\n        ///\n        /// Rasterization outside the given path is discarded.\n        ///\n        /// See [pop] for details about the operation stack. See [Clip] for different clip modes.\n        /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).\n        public void pushClipPath(Path path, Clip clipBehavior = Clip.antiAlias)\n        {\n            //assert(clipBehavior != null);\n            //assert(clipBehavior != Clip.none);\n            _pushClipPath(path, (int)clipBehavior);\n        }\n        void _pushClipPath(Path path, int clipBehavior)\n        {\n            // native 'SceneBuilder_pushClipPath';\n        }\n\n        /// Pushes an opacity operation onto the operation stack.\n        ///\n        /// The given alpha value is blended into the alpha value of the objects'\n        /// rasterization. An alpha value of 0 makes the objects entirely invisible.\n        /// An alpha value of 255 has no effect (i.e., the objects retain the current\n        /// opacity).\n        ///\n        /// See [pop] for details about the operation stack.\n        public void pushOpacity(int alpha, Offset offset = null)\n        {\n            if (offset == null)\n                offset = Offset.zero;\n\n            _pushOpacity(alpha, offset.dx, offset.dy);\n        }\n        void _pushOpacity(int alpha, double dx, double dy)\n        {\n            // native 'SceneBuilder_pushOpacity';\n        }\n\n        /// Pushes a color filter operation onto the operation stack.\n        ///\n        /// The given color is applied to the objects' rasterization using the given\n        /// blend mode.\n        ///\n        /// See [pop] for details about the operation stack.\n        public void pushColorFilter(Color color, BlendMode blendMode)\n        {\n            _pushColorFilter(color.value, (int)blendMode);\n        }\n        void _pushColorFilter(uint color, int blendMode)\n        {\n            // native 'SceneBuilder_pushColorFilter';\n        }\n\n        /// Pushes a backdrop filter operation onto the operation stack.\n        ///\n        /// The given filter is applied to the current contents of the scene prior to\n        /// rasterizing the given objects.\n        ///\n        /// See [pop] for details about the operation stack.\n        public void pushBackdropFilter(ImageFilter filter)\n        {\n            // native 'SceneBuilder_pushBackdropFilter';\n        }\n\n        /// Pushes a shader mask operation onto the operation stack.\n        ///\n        /// The given shader is applied to the object's rasterization in the given\n        /// rectangle using the given blend mode.\n        ///\n        /// See [pop] for details about the operation stack.\n        public void pushShaderMask(SKShader shader, Rect maskRect, BlendMode blendMode)\n        {\n            _pushShaderMask(shader,\n                            maskRect.left,\n                            maskRect.right,\n                            maskRect.top,\n                            maskRect.bottom,\n                            (int)blendMode);\n        }\n        void _pushShaderMask(SKShader shader,\n                             double maskRectLeft,\n                             double maskRectRight,\n                             double maskRectTop,\n                             double maskRectBottom,\n                             int blendMode)\n        {\n            // native 'SceneBuilder_pushShaderMask';\n        }\n\n        /// Pushes a physical layer operation for an arbitrary shape onto the\n        /// operation stack.\n        ///\n        /// By default, the layer's content will not be clipped (clip = [Clip.none]).\n        /// If clip equals [Clip.hardEdge], [Clip.antiAlias], or [Clip.antiAliasWithSaveLayer],\n        /// then the content is clipped to the given shape defined by [path].\n        ///\n        /// If [elevation] is greater than 0.0, then a shadow is drawn around the layer.\n        /// [shadowColor] defines the color of the shadow if present and [color] defines the\n        /// color of the layer background.\n        ///\n        /// See [pop] for details about the operation stack, and [Clip] for different clip modes.\n        // ignore: deprecated_member_use\n        public NativeEngineLayer pushPhysicalShape(Path path, double elevation, Color color, Color shadowColor, Clip clipBehavior = Clip.none)\n        {\n            return _pushPhysicalShape(path, elevation, color.value, shadowColor?.value ?? 0xFF000000, (int)clipBehavior);\n        }\n        NativeEngineLayer _pushPhysicalShape(Path path, double elevation, uint color, uint shadowColor, int clipBehavior)\n        {\n            // native 'SceneBuilder_pushPhysicalShape';\n            return null; // Tmp to resolve build\n        }\n\n        /// Ends the effect of the most recently pushed operation.\n        ///\n        /// Internally the scene builder maintains a stack of operations. Each of the\n        /// operations in the stack applies to each of the objects added to the scene.\n        /// Calling this function removes the most recently added operation from the\n        /// stack.\n        public void pop()\n        {\n            this.Pop();\n            // [DONE] native 'SceneBuilder_pop';\n        }\n\n        /// Add a retained engine layer subtree from previous frames.\n        ///\n        /// All the engine layers that are in the subtree of the retained layer will\n        /// be automatically appended to the current engine layer tree.\n        ///\n        /// Therefore, when implementing a subclas of the [Layer] concept defined in\n        /// the rendering layer of Flutter's framework, once this is called, there's\n        /// no need to call [addToScene] for its children layers.\n        public NativeEngineLayer addRetained(NativeEngineLayer retainedLayer)\n        {\n            // native 'SceneBuilder_addRetained';\n            return null; // Tmp to resolve build\n        }\n\n        /// Adds an object to the scene that displays performance statistics.\n        ///\n        /// Useful during development to assess the performance of the application.\n        /// The enabledOptions controls which statistics are displayed. The bounds\n        /// controls where the statistics are displayed.\n        ///\n        /// enabledOptions is a bit field with the following bits defined:\n        ///  - 0x01: displayRasterizerStatistics - show GPU thread frame time\n        ///  - 0x02: visualizeRasterizerStatistics - graph GPU thread frame times\n        ///  - 0x04: displayEngineStatistics - show UI thread frame time\n        ///  - 0x08: visualizeEngineStatistics - graph UI thread frame times\n        /// Set enabledOptions to 0x0F to enable all the currently defined features.\n        ///\n        /// The \"UI thread\" is the thread that includes all the execution of\n        /// the main Dart isolate (the isolate that can call\n        /// [Window.render]). The UI thread frame time is the total time\n        /// spent executing the [Window.onBeginFrame] callback. The \"GPU\n        /// thread\" is the thread (running on the CPU) that subsequently\n        /// processes the [Scene] provided by the Dart code to turn it into\n        /// GPU commands and send it to the GPU.\n        ///\n        /// See also the [PerformanceOverlayOption] enum in the rendering library.\n        /// for more details.\n        // Values above must match constants in //engine/src/sky/compositor/performance_overlay_layer.h\n        public void addPerformanceOverlay(int enabledOptions, Rect bounds)\n        {\n            _addPerformanceOverlay(enabledOptions,\n                                   bounds.left,\n                                   bounds.right,\n                                   bounds.top,\n                                   bounds.bottom);\n        }\n        void _addPerformanceOverlay(int enabledOptions,\n                                    double left,\n                                    double right,\n                                    double top,\n                                    double bottom)\n        {\n            // native 'SceneBuilder_addPerformanceOverlay';\n        }\n\n        /// Adds a [Picture] to the scene.\n        ///\n        /// The picture is rasterized at the given offset.\n        public void addPicture(Offset offset, SKPicture picture, bool isComplexHint = false, bool willChangeHint = false)\n        {\n            int hints = 0;\n            if (isComplexHint)\n                hints |= 1;\n            if (willChangeHint)\n                hints |= 2;\n            _addPicture(offset.dx, offset.dy, picture, hints);\n        }\n        void _addPicture(double dx, double dy, SKPicture picture, int hints)\n        {\n            this.AddPicture(dx, dy, picture, hints);\n            // [DONE] native 'SceneBuilder_addPicture';\n        }\n\n        /// Adds a backend texture to the scene.\n        ///\n        /// The texture is scaled to the given size and rasterized at the given offset.\n        ///\n        /// If `freeze` is true the texture that is added to the scene will not\n        /// be updated with new frames. `freeze` is used when resizing an embedded\n        /// Android view: When resizing an Android view there is a short period during\n        /// which the framework cannot tell if the newest texture frame has the\n        /// previous or new size, to workaround this the framework \"freezes\" the\n        /// texture just before resizing the Android view and unfreezes it when it is\n        /// certain that a frame with the new size is ready.\n        public void addTexture(int textureId, Offset offset = null, double width = 0.0, double height = 0.0, bool freeze = false)\n        {\n            if (offset == null)\n                offset = Offset.zero;\n\n            //assert(offset != null, 'Offset argument was null');\n            _addTexture(offset.dx, offset.dy, width, height, textureId, freeze);\n        }\n        void _addTexture(double dx, double dy, double width, double height, int textureId, bool freeze)\n        {\n            // native 'SceneBuilder_addTexture';\n        }\n\n        /// Adds a platform view (e.g an iOS UIView) to the scene.\n        ///\n        /// This is work in progress and is not currently supported on any platform.\n        public void addPlatformView(int viewId, Offset offset = null, double width = 0.0, double height = 0.0)\n        {\n            if (offset == null)\n                offset = Offset.zero;\n            //assert(offset != null, 'Offset argument was null');\n            _addPlatformView(offset.dx, offset.dy, width, height, viewId);\n        }\n        void _addPlatformView(double dx, double dy, double width, double height, int viewId)\n        {\n            // native 'SceneBuilder_addPlatformView';\n        }\n\n        /// (Fuchsia-only) Adds a scene rendered by another application to the scene\n        /// for this application.\n        public void addChildScene(\n                  Offset offset = null,\n          double width = 0.0,\n          double height = 0.0,\n          SceneHost sceneHost = null,\n          bool hitTestable = true\n        )\n        {\n            if (offset == null)\n                offset = Offset.zero;\n\n            _addChildScene(offset.dx,\n                           offset.dy,\n                           width,\n                           height,\n                           sceneHost,\n                           hitTestable);\n        }\n        void _addChildScene(double dx,\n                            double dy,\n                            double width,\n                            double height,\n                            SceneHost sceneHost,\n                            bool hitTestable)\n        {\n            // native 'SceneBuilder_addChildScene';\n        }\n\n\n        /// Sets a threshold after which additional debugging information should be recorded.\n        ///\n        /// Currently this interface is difficult to use by end-developers. If you're\n        /// interested in using this feature, please contact [flutter-dev](https://groups.google.com/forum/#!forum/flutter-dev).\n        /// We'll hopefully be able to figure out how to make this feature more useful\n        /// to you.\n        public void setRasterizerTracingThreshold(int frameInterval)\n        {\n            // native 'SceneBuilder_setRasterizerTracingThreshold';\n        }\n\n\n        /// Sets whether the raster cache should checkerboard cached entries. This is\n        /// only useful for debugging purposes.\n        ///\n        /// The compositor can sometimes decide to cache certain portions of the\n        /// widget hierarchy. Such portions typically don't change often from frame to\n        /// frame and are expensive to render. This can speed up overall rendering. However,\n        /// there is certain upfront cost to constructing these cache entries. And, if\n        /// the cache entries are not used very often, this cost may not be worth the\n        /// speedup in rendering of subsequent frames. If the developer wants to be certain\n        /// that populating the raster cache is not causing stutters, this option can be\n        /// set. Depending on the observations made, hints can be provided to the compositor\n        /// that aid it in making better decisions about caching.\n        ///\n        /// Currently this interface is difficult to use by end-developers. If you're\n        /// interested in using this feature, please contact [flutter-dev](https://groups.google.com/forum/#!forum/flutter-dev).\n        public void setCheckerboardRasterCacheImages(bool checkerboard)\n        {\n            // native 'SceneBuilder_setCheckerboardRasterCacheImages';\n        }\n\n        /// Sets whether the compositor should checkerboard layers that are rendered\n        /// to offscreen bitmaps.\n        ///\n        /// This is only useful for debugging purposes.\n        public void setCheckerboardOffscreenLayers(bool checkerboard)\n        {\n            // native 'SceneBuilder_setCheckerboardOffscreenLayers';\n        }\n\n        /// Finishes building the scene.\n        ///\n        /// Returns a [Scene] containing the objects that have been added to\n        /// this scene builder. The [Scene] can then be displayed on the\n        /// screen with [Window.render].\n        ///\n        /// After calling this function, the scene builder object is invalid and\n        /// cannot be used further.\n        public Scene build()\n        {\n            return this.Build();\n            // [DONE] native 'SceneBuilder_build';\n        }\n    }\n\n    /// (Fuchsia-only) Hosts content provided by another application.\n    public class SceneHost : NativeFieldWrapperClass2\n    {\n        /// Creates a host for a child scene.\n        ///\n        /// The export token is bound to a scene graph node which acts as a container\n        /// for the child's content.  The creator of the scene host is responsible for\n        /// sending the corresponding import token (the other endpoint of the event pair)\n        /// to the child.\n        ///\n        /// The export token is a dart:zircon Handle, but that type isn't\n        /// available here. This is called by ChildViewConnection in\n        /// //topaz/public/lib/ui/flutter/.\n        ///\n        /// The scene host takes ownership of the provided export token handle.\n        public SceneHost(object exportTokenHandle)\n        {\n            _constructor(exportTokenHandle);\n        }\n        void _constructor(object exportTokenHandle)\n        {\n            // native 'SceneHost_constructor';\n        }\n\n        /// Releases the resources associated with the child scene host.\n        ///\n        /// After calling this function, the child scene host cannot be used further.\n        public void dispose()\n        {\n            // native 'SceneHost_dispose';\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/FlutterSurface.cs",
    "content": "﻿using SkiaSharp;\n\nnamespace FlutterBinding.UI\n{\n    public class FlutterSurface\n    {\n        private readonly float _scale;\n\n        public FlutterSurface(float scale)\n        {\n            _scale = scale;\n        }\n\n        public void OnPaintSurface(SKSurface surface, SKImageInfo info)\n        {\n            var canvas = surface.Canvas;\n\n            // get the screen density for scaling\n            var scaledSize = new SKSize(info.Width / _scale, info.Height / _scale);\n\n            // handle the device screen density\n            canvas.Scale(_scale);\n\n            // make sure the canvas is blank\n            canvas.Clear(new SKColor(0,145, 234, 255));\n\n            // draw some text\n            var paint = new SKPaint\n            {\n                Color       = SKColors.WhiteSmoke,\n                IsAntialias = true,\n                Style       = SKPaintStyle.Fill,\n                TextAlign   = SKTextAlign.Center,\n                TextSize    = 24\n            };\n            var coord = new SKPoint(scaledSize.Width / 2, (scaledSize.Height + paint.TextSize) / 2);\n            canvas.DrawText(\"Xamarin.Flutter\", coord, paint);\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Geometry.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing static FlutterBinding.UI.Lerp;\nusing static FlutterBinding.Mapping.Helper;\n\nnamespace FlutterBinding.UI\n{\n\n    /// Base class for [Size] and [Offset], which are both ways to describe\n    /// a distance as a two-dimensional axis-aligned vector.\n    public abstract class OffsetBase\n    {\n        /// Abstract const constructor. This constructor enables subclasses to provide\n        /// const constructors so that they can be used in const expressions.\n        ///\n        /// The first argument sets the horizontal component, and the second the\n        /// vertical component.\n        public OffsetBase(double _dx, double _dy)\n        {\n            this._dx = _dx;\n            this._dy = _dy;\n        }\n\n        protected readonly double _dx;\n        protected readonly double _dy;\n\n        /// Returns true if either component is [double.infinity], and false if both\n        /// are finite (or negative infinity, or NaN).\n        ///\n        /// This is different than comparing for equality with an instance that has\n        /// _both_ components set to [double.infinity].\n        ///\n        /// See also:\n        ///\n        ///  * [isFinite], which is true if both components are finite (and not NaN).\n        public bool isInfinite => _dx >= double.PositiveInfinity || _dy >= double.PositiveInfinity;\n\n        /// Whether both components are finite (neither infinite nor NaN).\n        ///\n        /// See also:\n        ///\n        ///  * [isInfinite], which returns true if either component is equal to\n        ///    positive infinity.\n        public bool isFinite => _dx.isFinite() && _dy.isFinite();\n\n        /// Less-than operator. Compares an [Offset] or [Size] to another [Offset] or\n        /// [Size], and returns true if both the horizontal and vertical values of the\n        /// left-hand-side operand are smaller than the horizontal and vertical values\n        /// of the right-hand-side operand respectively. Returns false otherwise.\n        ///\n        /// This is a partial ordering. It is possible for two values to be neither\n        /// less, nor greater than, nor equal to, another.\n        public static bool operator <(OffsetBase offset, OffsetBase other) => offset._dx < other._dx && offset._dy < other._dy;\n\n        /// Less-than-or-equal-to operator. Compares an [Offset] or [Size] to another\n        /// [Offset] or [Size], and returns true if both the horizontal and vertical\n        /// values of the left-hand-side operand are smaller than or equal to the\n        /// horizontal and vertical values of the right-hand-side operand\n        /// respectively. Returns false otherwise.\n        ///\n        /// This is a partial ordering. It is possible for two values to be neither\n        /// less, nor greater than, nor equal to, another.\n        public static bool operator <=(OffsetBase offset, OffsetBase other) => offset._dx <= other._dx && offset._dy <= other._dy;\n\n        /// Greater-than operator. Compares an [Offset] or [Size] to another [Offset]\n        /// or [Size], and returns true if both the horizontal and vertical values of\n        /// the left-hand-side operand are bigger than the horizontal and vertical\n        /// values of the right-hand-side operand respectively. Returns false\n        /// otherwise.\n        ///\n        /// This is a partial ordering. It is possible for two values to be neither\n        /// less, nor greater than, nor equal to, another.\n        public static bool operator >(OffsetBase offset, OffsetBase other) => offset._dx > other._dx && offset._dy > other._dy;\n\n        /// Greater-than-or-equal-to operator. Compares an [Offset] or [Size] to\n        /// another [Offset] or [Size], and returns true if both the horizontal and\n        /// vertical values of the left-hand-side operand are bigger than or equal to\n        /// the horizontal and vertical values of the right-hand-side operand\n        /// respectively. Returns false otherwise.\n        ///\n        /// This is a partial ordering. It is possible for two values to be neither\n        /// less, nor greater than, nor equal to, another.\n        public static bool operator >=(OffsetBase offset, OffsetBase other) => offset._dx > other._dx && offset._dy >= other._dy;\n\n        /// Equality operator. Compares an [Offset] or [Size] to another [Offset] or\n        /// [Size], and returns true if the horizontal and vertical values of the\n        /// left-hand-side operand are equal to the horizontal and vertical values of\n        /// the right-hand-side operand respectively. Returns false otherwise.\n\n        public static bool operator ==(OffsetBase offset, Object other)\n        {\n            if (!(other is OffsetBase))\n                return false;\n            OffsetBase typedOther = (OffsetBase)other;\n            return offset._dx == typedOther._dx &&\n                   offset._dy == typedOther._dy;\n        }\n\n        public static bool operator !=(OffsetBase offset, Object other) => !(offset == other);\n\n        public int hashCode => hashValues(_dx, _dy);\n\n        public String toString() => $\"{nameof(OffsetBase)}({_dx.toStringAsFixed(1)}, {_dy.toStringAsFixed(1)})\";\n    }\n\n    /// An immutable 2D floating-point offset.\n    ///\n    /// Generally speaking, Offsets can be interpreted in two ways:\n    ///\n    /// 1. As representing a point in Cartesian space a specified distance from a\n    ///    separately-maintained origin. For example, the top-left position of\n    ///    children in the [RenderBox] protocol is typically represented as an\n    ///    [Offset] from the top left of the parent box.\n    ///\n    /// 2. As a vector that can be applied to coordinates. For example, when\n    ///    painting a [RenderObject], the parent is passed an [Offset] from the\n    ///    screen's origin which it can add to the offsets of its children to find\n    ///    the [Offset] from the screen's origin to each of the children.\n    ///\n    /// Because a particular [Offset] can be interpreted as one sense at one time\n    /// then as the other sense at a later time, the same class is used for both\n    /// senses.\n    ///\n    /// See also:\n    ///\n    ///  * [Size], which represents a vector describing the size of a rectangle.\n    public class Offset : OffsetBase\n    {\n        /// Creates an offset. The first argument sets [dx], the horizontal component,\n        /// and the second sets [dy], the vertical component.\n        public Offset(double dx, double dy) : base(dx, dy) { }\n\n        /// The x component of the offset.\n        ///\n        /// The y component is given by [dy].\n        public double dx => _dx;\n\n        /// The y component of the offset.\n        ///\n        /// The x component is given by [dx].\n        public double dy => _dy;\n\n        /// The magnitude of the offset.\n        ///\n        /// If you need this value to compare it to another [Offset]'s distance,\n        /// consider using [distanceSquared] instead, since it is cheaper to compute.\n        public double distance => Math.Sqrt(_dx * _dx + _dy * _dy);\n\n        /// The square of the magnitude of the offset.\n        ///\n        /// This is cheaper than computing the [distance] itself.\n        public double distanceSquared => _dx * _dx + _dy * _dy;\n\n        /// The angle of this offset as radians clockwise from the positive x-axis, in\n        /// the range -[pi] to [pi], assuming positive values of the x-axis go to the\n        /// left and positive values of the y-axis go down.\n        ///\n        /// Zero means that [dy] is zero and [dx] is zero or positive.\n        ///\n        /// Values from zero to [pi]/2 indicate positive values of [dx] and [dy], the\n        /// bottom-right quadrant.\n        ///\n        /// Values from [pi]/2 to [pi] indicate negative values of [dx] and positive\n        /// values of [dy], the bottom-left quadrant.\n        ///\n        /// Values from zero to -[pi]/2 indicate positive values of [dx] and negative\n        /// values of [dy], the top-right quadrant.\n        ///\n        /// Values from -[pi]/2 to -[pi] indicate negative values of [dx] and [dy],\n        /// the top-left quadrant.\n        ///\n        /// When [dy] is zero and [dx] is negative, the [direction] is [pi].\n        ///\n        /// When [dx] is zero, [direction] is [pi]/2 if [dy] is positive and -[pi]/2\n        /// if [dy] is negative.\n        ///\n        /// See also:\n        ///\n        ///  * [distance], to compute the magnitude of the vector.\n        ///  * [Canvas.rotate], which uses the same convention for its angle.\n        public double direction => Math.Atan2(dy, dx);\n\n        /// An offset with zero magnitude.\n        ///\n        /// This can be used to represent the origin of a coordinate space.\n        public static Offset zero = new Offset(0.0, 0.0);\n\n        /// An offset with infinite x and y components.\n        ///\n        /// See also:\n        ///\n        ///  * [isInfinite], which checks whether either component is infinite.\n        ///  * [isFinite], which checks whether both components are finite.\n        // This is included for completeness, because [Size.infinite] exists.\n        public static Offset infinite = new Offset(double.PositiveInfinity, double.PositiveInfinity);\n\n        /// Returns a new offset with the x component scaled by `scaleX` and the y\n        /// component scaled by `scaleY`.\n        ///\n        /// If the two scale arguments are the same, consider using the `*` operator\n        /// instead:\n        ///\n        /// ```dart\n        /// Offset a = const Offset(10.0, 10.0);\n        /// Offset b = a * 2.0; // same as: a.scale(2.0, 2.0)\n        /// ```\n        ///\n        /// If the two arguments are -1, consider using the unary `-` operator\n        /// instead:\n        ///\n        /// ```dart\n        /// Offset a = const Offset(10.0, 10.0);\n        /// Offset b = -a; // same as: a.scale(-1.0, -1.0)\n        /// ```\n        public Offset scale(double scaleX, double scaleY) => new Offset(dx * scaleX, dy * scaleY);\n\n        /// Returns a new offset with translateX added to the x component and\n        /// translateY added to the y component.\n        ///\n        /// If the arguments come from another [Offset], consider using the `+` or `-`\n        /// operators instead:\n        ///\n        /// ```dart\n        /// Offset a = const Offset(10.0, 10.0);\n        /// Offset b = const Offset(10.0, 10.0);\n        /// Offset c = a + b; // same as: a.translate(b.dx, b.dy)\n        /// Offset d = a - b; // same as: a.translate(-b.dx, -b.dy)\n        /// ```\n        public Offset translate(double translateX, double translateY) => new Offset(dx + translateX, dy + translateY);\n\n        /// Unary negation operator.\n        ///\n        /// Returns an offset with the coordinates negated.\n        ///\n        /// If the [Offset] represents an arrow on a plane, this operator returns the\n        /// same arrow but pointing in the reverse direction.\n        public static Offset operator -(Offset offset) => new Offset(-offset.dx, -offset.dy);\n\n        /// Binary subtraction operator.\n        ///\n        /// Returns an offset whose [dx] value is the left-hand-side operand's [dx]\n        /// minus the right-hand-side operand's [dx] and whose [dy] value is the\n        /// left-hand-side operand's [dy] minus the right-hand-side operand's [dy].\n        ///\n        /// See also [translate].\n        public static Offset operator -(Offset offset, Offset other) => new Offset(offset.dx - other.dx, offset.dy - other.dy);\n\n        /// Binary addition operator.\n        ///\n        /// Returns an offset whose [dx] value is the sum of the [dx] values of the\n        /// two operands, and whose [dy] value is the sum of the [dy] values of the\n        /// two operands.\n        ///\n        /// See also [translate].\n        public static Offset operator +(Offset offset, Offset other) => new Offset(offset.dx + other.dx, offset.dy + other.dy);\n\n        /// Multiplication operator.\n        ///\n        /// Returns an offset whose coordinates are the coordinates of the\n        /// left-hand-side operand (an Offset) multiplied by the scalar\n        /// right-hand-side operand (a double).\n        ///\n        /// See also [scale].\n        public static Offset operator *(Offset offset, double operand) => new Offset(offset.dx * operand, offset.dy * operand);\n\n        /// Division operator.\n        ///\n        /// Returns an offset whose coordinates are the coordinates of the\n        /// left-hand-side operand (an Offset) divided by the scalar right-hand-side\n        /// operand (a double).\n        ///\n        /// See also [scale].\n        public static Offset operator /(Offset offset, double operand) => new Offset(offset.dx / operand, offset.dy / operand);\n\n        /// Integer (truncating) division operator.\n        ///\n        /// Returns an offset whose coordinates are the coordinates of the\n        /// left-hand-side operand (an Offset) divided by the scalar right-hand-side\n        /// operand (a double), rounded towards zero.\n        //public Offset operator ~/ (double operand) => new Offset((dx ~/ operand).toDouble(), (dy ~/ operand).toDouble());\n\n        /// Modulo (remainder) operator.\n        ///\n        /// Returns an offset whose coordinates are the remainder of dividing the\n        /// coordinates of the left-hand-side operand (an Offset) by the scalar\n        /// right-hand-side operand (a double).\n        public static Offset operator %(Offset offset, double operand) => new Offset(offset.dx % operand, offset.dy % operand);\n\n        /// Rectangle constructor operator.\n        ///\n        /// Combines an [Offset] and a [Size] to form a [Rect] whose top-left\n        /// coordinate is the point given by adding this offset, the left-hand-side\n        /// operand, to the origin, and whose size is the right-hand-side operand.\n        ///\n        /// ```dart\n        /// Rect myRect = Offset.zero & const Size(100.0, 100.0);\n        /// // same as: new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)\n        /// ```\n        public static Rect operator &(Offset offset, Size other) => Rect.fromLTWH(offset.dx, offset.dy, other.width, other.height);\n\n        /// Linearly interpolate between two offsets.\n        ///\n        /// If either offset is null, this function interpolates from [Offset.zero].\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static Offset lerp(Offset a, Offset b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return b * t;\n            if (b == null)\n                return a * (1.0 - t);\n            return new Offset(lerpDouble(a.dx, b.dx, t), lerpDouble(a.dy, b.dy, t));\n        }\n\n        /// Compares two Offsets for equality.\n        public static bool operator ==(Offset offset, Object other)\n        {\n            if (!(other is Offset))\n                return false;\n            Offset typedOther = (Offset)other;\n            return offset._dx == typedOther._dx &&\n                   offset._dy == typedOther._dy;\n        }\n\n        public static bool operator !=(Offset offset, Object other) => !(offset == other);\n\n        public int hashCode => hashValues(_dx, _dy);\n\n        public String toString() => $\"Offset({dx.toStringAsFixed(1)}, {dy.toStringAsFixed(1)})\";\n    }\n\n    /// Holds a 2D floating-point size.\n    ///\n    /// You can think of this as an [Offset] from the origin.\n    public class Size : OffsetBase\n    {\n        /// Creates a [Size] with the given [width] and [height].\n        public Size(double width, double height) : base(width, height) { }\n\n        /// Creates an instance of [Size] that has the same values as another.\n        // Used by the rendering library's _DebugSize hack.\n        public static Size copy(Size source) => new Size(source.width, source.height);\n\n        /// Creates a square [Size] whose [width] and [height] are the given dimension.\n        ///\n        /// See also:\n        ///\n        ///  * [new Size.fromRadius], which is more convenient when the available size\n        ///    is the radius of a circle.\n        public static Size square(double dimension) => new Size(dimension, dimension);\n\n        /// Creates a [Size] with the given [width] and an infinite [height].\n        public static Size fromWidth(double width) => new Size(width, double.PositiveInfinity);\n\n        /// Creates a [Size] with the given [height] and an infinite [width].\n        public static Size fromHeight(double height) => new Size(double.PositiveInfinity, height);\n\n        /// Creates a square [Size] whose [width] and [height] are twice the given\n        /// dimension.\n        ///\n        /// This is a square that contains a circle with the given radius.\n        ///\n        /// See also:\n        ///\n        ///  * [new Size.square], which creates a square with the given dimension.\n        public static Size fromRadius(double radius) => new Size(radius * 2.0, radius * 2.0);\n\n        /// The horizontal extent of this size.\n        public double width => _dx;\n\n        /// The vertical extent of this size.\n        public double height => _dy;\n\n        /// An empty size, one with a zero width and a zero height.\n        public static Size zero = new Size(0.0, 0.0);\n\n        /// A size whose [width] and [height] are infinite.\n        ///\n        /// See also:\n        ///\n        ///  * [isInfinite], which checks whether either dimension is infinite.\n        ///  * [isFinite], which checks whether both dimensions are finite.\n        public static Size infinite = new Size(double.PositiveInfinity, double.PositiveInfinity);\n\n        /// Whether this size encloses a non-zero area.\n        ///\n        /// Negative areas are considered empty.\n        public bool isEmpty => width <= 0.0 || height <= 0.0;\n\n        /// Binary subtraction operator for [Size].\n        ///\n        /// Subtracting a [Size] from a [Size] returns the [Offset] that describes how\n        /// much bigger the left-hand-side operand is than the right-hand-side\n        /// operand. Adding that resulting [Offset] to the [Size] that was the\n        /// right-hand-side operand would return a [Size] equal to the [Size] that was\n        /// the left-hand-side operand. (i.e. if `sizeA - sizeB -> offsetA`, then\n        /// `offsetA + sizeB -> sizeA`)\n        ///\n        /// Subtracting an [Offset] from a [Size] returns the [Size] that is smaller than\n        /// the [Size] operand by the difference given by the [Offset] operand. In other\n        /// words, the returned [Size] has a [width] consisting of the [width] of the\n        /// left-hand-side operand minus the [Offset.dx] dimension of the\n        /// right-hand-side operand, and a [height] consisting of the [height] of the\n        /// left-hand-side operand minus the [Offset.dy] dimension of the\n        /// right-hand-side operand.\n        public static OffsetBase operator -(Size first, OffsetBase other)\n        {\n            if (other is Size size)\n                return new Offset(first.width - size.width, first.height - size.height);\n            if (other is Offset offset)\n                return new Size(first.width - offset.dx, first.height - offset.dy);\n            throw new ArgumentException(other.toString());\n        }\n\n        /// Binary addition operator for adding an [Offset] to a [Size].\n        ///\n        /// Returns a [Size] whose [width] is the sum of the [width] of the\n        /// left-hand-side operand, a [Size], and the [Offset.dx] dimension of the\n        /// right-hand-side operand, an [Offset], and whose [height] is the sum of the\n        /// [height] of the left-hand-side operand and the [Offset.dy] dimension of\n        /// the right-hand-side operand.\n        public static Size operator +(Size size, Offset other) => new Size(size.width + other.dx, size.height + other.dy);\n\n        /// Multiplication operator.\n        ///\n        /// Returns a [Size] whose dimensions are the dimensions of the left-hand-side\n        /// operand (a [Size]) multiplied by the scalar right-hand-side operand (a\n        /// [double]).\n        public static Size operator *(Size size, double operand) => new Size(size.width * operand, size.height * operand);\n\n        /// Division operator.\n        ///\n        /// Returns a [Size] whose dimensions are the dimensions of the left-hand-side\n        /// operand (a [Size]) divided by the scalar right-hand-side operand (a\n        /// [double]).\n        public static Size operator /(Size size, double operand) => new Size(size.width / operand, size.height / operand);\n\n        /// Integer (truncating) division operator.\n        ///\n        /// Returns a [Size] whose dimensions are the dimensions of the left-hand-side\n        /// operand (a [Size]) divided by the scalar right-hand-side operand (a\n        /// [double]), rounded towards zero.\n        //public Size operator ~/ (double operand) => new Size((width ~/ operand).toDouble(), (height ~/ operand).toDouble());\n\n        /// Modulo (remainder) operator.\n        ///\n        /// Returns a [Size] whose dimensions are the remainder of dividing the\n        /// left-hand-side operand (a [Size]) by the scalar right-hand-side operand (a\n        /// [double]).\n        public static Size operator %(Size size, double operand) => new Size(size.width % operand, size.height % operand);\n\n        /// The lesser of the magnitudes of the [width] and the [height].\n        public double shortestSide => Math.Min(width.abs(), height.abs());\n\n        /// The greater of the magnitudes of the [width] and the [height].\n        public double longestSide => Math.Max(width.abs(), height.abs());\n\n        // Convenience methods that do the equivalent of calling the similarly named\n        // methods on a Rect constructed from the given origin and this size.\n\n        /// The offset to the intersection of the top and left edges of the rectangle\n        /// described by the given [Offset] (which is interpreted as the top-left corner)\n        /// and this [Size].\n        ///\n        /// See also [Rect.topLeft].\n        public Offset topLeft(Offset origin) => origin;\n\n        /// The offset to the center of the top edge of the rectangle described by the\n        /// given offset (which is interpreted as the top-left corner) and this size.\n        ///\n        /// See also [Rect.topCenter].\n        public Offset topCenter(Offset origin) => new Offset(origin.dx + width / 2.0, origin.dy);\n\n        /// The offset to the intersection of the top and right edges of the rectangle\n        /// described by the given offset (which is interpreted as the top-left corner)\n        /// and this size.\n        ///\n        /// See also [Rect.topRight].\n        public Offset topRight(Offset origin) => new Offset(origin.dx + width, origin.dy);\n\n        /// The offset to the center of the left edge of the rectangle described by the\n        /// given offset (which is interpreted as the top-left corner) and this size.\n        ///\n        /// See also [Rect.centerLeft].\n        public Offset centerLeft(Offset origin) => new Offset(origin.dx, origin.dy + height / 2.0);\n\n        /// The offset to the point halfway between the left and right and the top and\n        /// bottom edges of the rectangle described by the given offset (which is\n        /// interpreted as the top-left corner) and this size.\n        ///\n        /// See also [Rect.center].\n        public Offset center(Offset origin) => new Offset(origin.dx + width / 2.0, origin.dy + height / 2.0);\n\n        /// The offset to the center of the right edge of the rectangle described by the\n        /// given offset (which is interpreted as the top-left corner) and this size.\n        ///\n        /// See also [Rect.centerLeft].\n        public Offset centerRight(Offset origin) => new Offset(origin.dx + width, origin.dy + height / 2.0);\n\n        /// The offset to the intersection of the bottom and left edges of the\n        /// rectangle described by the given offset (which is interpreted as the\n        /// top-left corner) and this size.\n        ///\n        /// See also [Rect.bottomLeft].\n        public Offset bottomLeft(Offset origin) => new Offset(origin.dx, origin.dy + height);\n\n        /// The offset to the center of the bottom edge of the rectangle described by\n        /// the given offset (which is interpreted as the top-left corner) and this\n        /// size.\n        ///\n        /// See also [Rect.bottomLeft].\n        public Offset bottomCenter(Offset origin) => new Offset(origin.dx + width / 2.0, origin.dy + height);\n\n        /// The offset to the intersection of the bottom and right edges of the\n        /// rectangle described by the given offset (which is interpreted as the\n        /// top-left corner) and this size.\n        ///\n        /// See also [Rect.bottomRight].\n        public Offset bottomRight(Offset origin) => new Offset(origin.dx + width, origin.dy + height);\n\n        /// Whether the point specified by the given offset (which is assumed to be\n        /// relative to the top left of the size) lies between the left and right and\n        /// the top and bottom edges of a rectangle of this size.\n        ///\n        /// Rectangles include their top and left edges but exclude their bottom and\n        /// right edges.\n        public bool contains(Offset offset)\n        {\n            return offset.dx >= 0.0 && offset.dx < width && offset.dy >= 0.0 && offset.dy < height;\n        }\n\n        /// A [Size] with the [width] and [height] swapped.\n        public Size flipped => new Size(height, width);\n\n        /// Linearly interpolate between two sizes\n        ///\n        /// If either size is null, this function interpolates from [Size.zero].\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static Size lerp(Size a, Size b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return b * t;\n            if (b == null)\n                return a * (1.0 - t);\n            return new Size(lerpDouble(a.width, b.width, t), lerpDouble(a.height, b.height, t));\n        }\n\n        /// Compares two Sizes for equality.\n        // We don't compare the runtimeType because of _DebugSize in the framework.\n        public static bool operator ==(Size size, Object other)\n        {\n            if (!(other is Size))\n                return false;\n            Size typedOther = (Size)other;\n            return size._dx == typedOther._dx &&\n                   size._dy == typedOther._dy;\n        }\n\n        public static bool operator !=(Size size, Object other) => !(size == other);\n\n        public int hashCode => hashValues(_dx, _dy);\n\n        public String toString() => $\"Size({width.toStringAsFixed(1)}, {height.toStringAsFixed(1)})\";\n    }\n\n    /// An immutable, 2D, axis-aligned, floating-point rectangle whose coordinates\n    /// are relative to a given origin.\n    ///\n    /// A Rect can be created with one its constructors or from an [Offset] and a\n    /// [Size] using the `&` operator:\n    ///\n    /// ```dart\n    /// Rect myRect = const Offset(1.0, 2.0) & const Size(3.0, 4.0);\n    /// ```\n    public class Rect\n    {\n        private Rect() { }\n\n        private Rect(double one, double two, double three, double four)\n        {\n            _value[0] = one;\n            _value[1] = two;\n            _value[2] = three;\n            _value[3] = four;\n        }\n\n        private Rect(List<double> values)\n        {\n            _value = values;\n        }\n\n        /// Construct a rectangle from its left, top, right, and bottom edges.\n        public static Rect fromLTRB(double left, double top, double right, double bottom)\n        {\n            return new Rect(left, top, right, bottom);\n        }\n\n        /// Construct a rectangle from its left and top edges, its width, and its\n        /// height.\n        ///\n        /// To construct a [Rect] from an [Offset] and a [Size], you can use the\n        /// rectangle constructor operator `&`. See [Offset.&].\n        public static Rect fromLTWH(double left, double top, double width, double height)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n                left,\n                top,\n                left + width,\n                top + height\n            };\n            return new Rect(list);\n        }\n\n        /// Construct a rectangle that bounds the given circle.\n        ///\n        /// The `center` argument is assumed to be an offset from the origin.\n        public static Rect fromCircle(Offset center = null, double radius = 0.0)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n               center.dx - radius,\n               center.dy - radius,\n               center.dx + radius,\n               center.dy + radius\n            };\n\n            return new Rect(list);\n        }\n\n        /// Construct the smallest rectangle that encloses the given offsets, treating\n        /// them as vectors from the origin.\n        public static Rect fromPoints(Offset a, Offset b)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n               Math.Min(a.dx, b.dx),\n               Math.Min(a.dy, b.dy),\n               Math.Max(a.dx, b.dx),\n               Math.Max(a.dy, b.dy)\n            };\n\n            return new Rect(list);\n        }\n\n        const int _kDataSize = 4;\n        public readonly List<double> _value = new List<double>(_kDataSize);\n\n        /// The offset of the left edge of this rectangle from the x axis.\n        public double left => _value[0];\n\n        /// The offset of the top edge of this rectangle from the y axis.\n        public double top => _value[1];\n\n        /// The offset of the right edge of this rectangle from the x axis.\n        public double right => _value[2];\n\n        /// The offset of the bottom edge of this rectangle from the y axis.\n        public double bottom => _value[3];\n\n        /// The distance between the left and right edges of this rectangle.\n        public double width => right - left;\n\n        /// The distance between the top and bottom edges of this rectangle.\n        public double height => bottom - top;\n\n        /// The distance between the upper-left corner and the lower-right corner of\n        /// this rectangle.\n        public Size size => new Size(width, height);\n\n        /// A rectangle with left, top, right, and bottom edges all at zero.\n        public static readonly Rect zero = new Rect();\n\n        public const double _giantScalar = 1.0E+9; // matches kGiantRect from default_layer_builder.cc\n\n        /// A rectangle that covers the entire coordinate space.\n        ///\n        /// This covers the space from -1e9,-1e9 to 1e9,1e9.\n        /// This is the space over which graphics operations are valid.\n        public static readonly Rect largest = Rect.fromLTRB(-_giantScalar, -_giantScalar, _giantScalar, _giantScalar);\n\n        /// Whether any of the coordinates of this rectangle are equal to positive infinity.\n        // included for consistency with Offset and Size\n        public bool isInfinite => left >= double.PositiveInfinity\n                                || top >= double.PositiveInfinity\n                                || right >= double.PositiveInfinity\n                                || bottom >= double.PositiveInfinity;\n\n\n        /// Whether all coordinates of this rectangle are finite.\n        public bool isFinite => left.isFinite() && top.isFinite() && right.isFinite() && bottom.isFinite();\n\n        /// Whether this rectangle encloses a non-zero area. Negative areas are\n        /// considered empty.\n        public bool isEmpty => left >= right || top >= bottom;\n\n        /// Returns a new rectangle translated by the given offset.\n        ///\n        /// To translate a rectangle by separate x and y components rather than by an\n        /// [Offset], consider [translate].\n        public Rect shift(Offset offset)\n        {\n            return Rect.fromLTRB(left + offset.dx, top + offset.dy, right + offset.dx, bottom + offset.dy);\n        }\n\n        /// Returns a new rectangle with translateX added to the x components and\n        /// translateY added to the y components.\n        ///\n        /// To translate a rectangle by an [Offset] rather than by separate x and y\n        /// components, consider [shift].\n        public Rect translate(double translateX, double translateY)\n        {\n            return Rect.fromLTRB(left + translateX, top + translateY, right + translateX, bottom + translateY);\n        }\n\n        /// Returns a new rectangle with edges moved outwards by the given delta.\n        public Rect inflate(double delta)\n        {\n            return Rect.fromLTRB(left - delta, top - delta, right + delta, bottom + delta);\n        }\n\n        /// Returns a new rectangle with edges moved inwards by the given delta.\n        public Rect deflate(double delta) => inflate(-delta);\n\n        /// Returns a new rectangle that is the intersection of the given\n        /// rectangle and this rectangle. The two rectangles must overlap\n        /// for this to be meaningful. If the two rectangles do not overlap,\n        /// then the resulting Rect will have a negative width or height.\n        public Rect intersect(Rect other)\n        {\n            return Rect.fromLTRB(\n              Math.Max(left, other.left),\n              Math.Max(top, other.top),\n              Math.Min(right, other.right),\n              Math.Min(bottom, other.bottom)\n            );\n        }\n\n        /// Returns a new rectangle which is the bounding box containing this\n        /// rectangle and the given rectangle.\n        public Rect expandToInclude(Rect other)\n        {\n            return Rect.fromLTRB(\n                Math.Min(left, other.left),\n                Math.Min(top, other.top),\n                Math.Max(right, other.right),\n                Math.Max(bottom, other.bottom));\n        }\n\n        /// Whether `other` has a nonzero area of overlap with this rectangle.\n        public bool overlaps(Rect other)\n        {\n            if (right <= other.left || other.right <= left)\n                return false;\n            if (bottom <= other.top || other.bottom <= top)\n                return false;\n            return true;\n        }\n\n        /// The lesser of the magnitudes of the [width] and the [height] of this\n        /// rectangle.\n        public double shortestSide => Math.Min(width.abs(), height.abs());\n\n        /// The greater of the magnitudes of the [width] and the [height] of this\n        /// rectangle.\n        public double longestSide => Math.Max(width.abs(), height.abs());\n\n        /// The offset to the intersection of the top and left edges of this rectangle.\n        ///\n        /// See also [Size.topLeft].\n        public Offset topLeft => new Offset(left, top);\n\n        /// The offset to the center of the top edge of this rectangle.\n        ///\n        /// See also [Size.topCenter].\n        public Offset topCenter => new Offset(left + width / 2.0, top);\n\n        /// The offset to the intersection of the top and right edges of this rectangle.\n        ///\n        /// See also [Size.topRight].\n        public Offset topRight => new Offset(right, top);\n\n        /// The offset to the center of the left edge of this rectangle.\n        ///\n        /// See also [Size.centerLeft].\n        public Offset centerLeft => new Offset(left, top + height / 2.0);\n\n        /// The offset to the point halfway between the left and right and the top and\n        /// bottom edges of this rectangle.\n        ///\n        /// See also [Size.center].\n        public Offset center => new Offset(left + width / 2.0, top + height / 2.0);\n\n        /// The offset to the center of the right edge of this rectangle.\n        ///\n        /// See also [Size.centerLeft].\n        public Offset centerRight => new Offset(right, top + height / 2.0);\n\n        /// The offset to the intersection of the bottom and left edges of this rectangle.\n        ///\n        /// See also [Size.bottomLeft].\n        public Offset bottomLeft => new Offset(left, bottom);\n\n        /// The offset to the center of the bottom edge of this rectangle.\n        ///\n        /// See also [Size.bottomLeft].\n        public Offset bottomCenter => new Offset(left + width / 2.0, bottom);\n\n        /// The offset to the intersection of the bottom and right edges of this rectangle.\n        ///\n        /// See also [Size.bottomRight].\n        public Offset bottomRight => new Offset(right, bottom);\n\n        /// Whether the point specified by the given offset (which is assumed to be\n        /// relative to the origin) lies between the left and right and the top and\n        /// bottom edges of this rectangle.\n        ///\n        /// Rectangles include their top and left edges but exclude their bottom and\n        /// right edges.\n        public bool contains(Offset offset)\n        {\n            return offset.dx >= left && offset.dx < right && offset.dy >= top && offset.dy < bottom;\n        }\n\n        /// Linearly interpolate between two rectangles.\n        ///\n        /// If either rect is null, [Rect.zero] is used as a substitute.\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static Rect lerp(Rect a, Rect b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);\n            if (b == null)\n            {\n                double k = 1.0 - t;\n                return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);\n            }\n            return Rect.fromLTRB(\n              lerpDouble(a.left, b.left, t),\n              lerpDouble(a.top, b.top, t),\n              lerpDouble(a.right, b.right, t),\n              lerpDouble(a.bottom, b.bottom, t));\n        }\n\n        //public static bool operator ==(Rect rect, Object other)\n        //{\n        //    if (identical(rect, other))\n        //        return true;\n        //    if (rect.GetType() != other.GetType())\n        //        return false;\n        //    Rect typedOther = (Rect)other;\n        //    for (int i = 0; i < _kDataSize; i += 1)\n        //    {\n        //        if (rect._value[i] != typedOther._value[i])\n        //            return false;\n        //    }\n        //    return true;\n        //}\n\n        //public static bool operator !=(Rect rect, Object other) => !(rect == other);\n\n        public int hashCode => hashList(_value);\n\n        public String toString() => $\"Rect.fromLTRB({left.toStringAsFixed(1)}, {top.toStringAsFixed(1)}, {right.toStringAsFixed(1)}, {bottom.toStringAsFixed(1)})\";\n    }\n\n    /// A radius for either circular or elliptical shapes.\n    public class Radius\n    {\n        /// Constructs a circular radius. [x] and [y] will have the same radius value.\n        public static Radius circular(double radius)\n        {\n            return elliptical(radius, radius);\n        }\n\n        /// Constructs an elliptical radius with the given radii.\n        public static Radius elliptical(double x, double y)\n        {\n            return new Radius(x, y);\n        }\n        private Radius(double x, double y)\n        {\n            this.x = x;\n            this.y = y;\n        }\n\n        /// The radius value on the horizontal axis.\n        public readonly double x;\n\n        /// The radius value on the vertical axis.\n        public readonly double y;\n\n        /// A radius with [x] and [y] values set to zero.\n        ///\n        /// You can use [Radius.zero] with [RRect] to have right-angle corners.\n        public static Radius zero = Radius.circular(0.0);\n\n        /// Unary negation operator.\n        ///\n        /// Returns a Radius with the distances negated.\n        ///\n        /// Radiuses with negative values aren't geometrically meaningful, but could\n        /// occur as part of expressions. For example, negating a radius of one pixel\n        /// and then adding the result to another radius is equivalent to subtracting\n        /// a radius of one pixel from the other.\n        public static Radius operator -(Radius radius) => Radius.elliptical(-radius.x, -radius.y);\n\n        /// Binary subtraction operator.\n        ///\n        /// Returns a radius whose [x] value is the left-hand-side operand's [x]\n        /// minus the right-hand-side operand's [x] and whose [y] value is the\n        /// left-hand-side operand's [y] minus the right-hand-side operand's [y].\n        public static Radius operator -(Radius radius, Radius other) => Radius.elliptical(radius.x - other.x, radius.y - other.y);\n\n        /// Binary addition operator.\n        ///\n        /// Returns a radius whose [x] value is the sum of the [x] values of the\n        /// two operands, and whose [y] value is the sum of the [y] values of the\n        /// two operands.\n        public static Radius operator +(Radius radius, Radius other) => Radius.elliptical(radius.x + other.x, radius.y + other.y);\n\n        /// Multiplication operator.\n        ///\n        /// Returns a radius whose coordinates are the coordinates of the\n        /// left-hand-side operand (a radius) multiplied by the scalar\n        /// right-hand-side operand (a double).\n        public static Radius operator *(Radius radius, double operand) => Radius.elliptical(radius.x * operand, radius.y * operand);\n\n        /// Division operator.\n        ///\n        /// Returns a radius whose coordinates are the coordinates of the\n        /// left-hand-side operand (a radius) divided by the scalar right-hand-side\n        /// operand (a double).\n        public static Radius operator /(Radius radius, double operand) => Radius.elliptical(radius.x / operand, radius.y / operand);\n\n        /// Integer (truncating) division operator.\n        ///\n        /// Returns a radius whose coordinates are the coordinates of the\n        /// left-hand-side operand (a radius) divided by the scalar right-hand-side\n        /// operand (a double), rounded towards zero.\n        // No divide and truncate operator in C#\n        //public static Radius operator ~/(double operand) => Radius.elliptical((x ~/ operand).toDouble(), (y ~/ operand).toDouble());\n\n        /// Modulo (remainder) operator.\n        ///\n        /// Returns a radius whose coordinates are the remainder of dividing the\n        /// coordinates of the left-hand-side operand (a radius) by the scalar\n        /// right-hand-side operand (a double).\n        public static Radius operator %(Radius radius, double operand) => Radius.elliptical(radius.x % operand, radius.y % operand);\n\n        /// Linearly interpolate between two radii.\n        ///\n        /// If either is null, this function substitutes [Radius.zero] instead.\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static Radius lerp(Radius a, Radius b, double t)\n        {\n            // assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return Radius.elliptical(b.x * t, b.y * t);\n            if (b == null)\n            {\n                double k = 1.0 - t;\n                return Radius.elliptical(a.x * k, a.y * k);\n            }\n            return Radius.elliptical(\n              lerpDouble(a.x, b.x, t),\n              lerpDouble(a.y, b.y, t));\n        }\n\n        public static bool operator ==(Radius radius, Object other)\n        {\n            if (identical(radius, other))\n                return true;\n            if (radius.GetType() != other.GetType())\n                return false;\n            Radius typedOther = (Radius)other;\n            return typedOther.x == radius.x && typedOther.y == radius.y;\n        }\n\n        public static bool operator !=(Radius radius, Object other) => !(radius == other);\n\n        public int hashCode => hashValues(x, y);\n\n        public String toString()\n        {\n            return x == y ? $\"Radius.circular({x.toStringAsFixed(1)})\" :\n                            $\"Radius.elliptical({x.toStringAsFixed(1)}, \" +\n                            $\"{y.toStringAsFixed(1)})\";\n        }\n    }\n\n    /// An immutable rounded rectangle with the custom radii for all four corners.\n    public class RRect\n    {\n        private RRect(List<double> value)\n        {\n            _value = value;\n        }\n\n        /// Construct a rounded rectangle from its left, top, right, and bottom edges,\n        /// and the same radii along its horizontal axis and its vertical axis.\n        public static RRect fromLTRBXY(double left, double top, double right, double bottom,\n                         double radiusX, double radiusY)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n                left,\n              top,\n              right,\n              bottom,\n             radiusX,\n              radiusY,\n              radiusX,\n              radiusY,\n             radiusX,\n             radiusY,\n             radiusX,\n              radiusY,\n            };\n\n            return new RRect(list);\n        }\n\n        /// Construct a rounded rectangle from its left, top, right, and bottom edges,\n        /// and the same radius in each corner.\n        public static RRect fromLTRBR(double left, double top, double right, double bottom,\n                        Radius radius)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n              left,\n              top,\n             right,\n              bottom,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y\n            };\n            return new RRect(list);\n        }\n\n        /// Construct a rounded rectangle from its bounding box and the same radii\n        /// along its horizontal axis and its vertical axis.\n        public static RRect fromRectXY(Rect rect, double radiusX, double radiusY)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n               rect.left,\n              rect.top,\n              rect.right,\n              rect.bottom,\n              radiusX,\n              radiusY,\n              radiusX,\n              radiusY,\n              radiusX,\n              radiusY,\n              radiusX,\n              radiusY\n            };\n            return new RRect(list);\n        }\n\n        /// Construct a rounded rectangle from its bounding box and a radius that is\n        /// the same in each corner.\n        public static RRect fromRectAndRadius(Rect rect, Radius radius)\n        {\n            var list = new List<double>(_kDataSize)\n            {\n               rect.left,\n              rect.top,\n              rect.right,\n              rect.bottom,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y,\n              radius.x,\n              radius.y\n            };\n            return new RRect(list);\n        }\n\n        /// Construct a rounded rectangle from its left, top, right, and bottom edges,\n        /// and topLeft, topRight, bottomRight, and bottomLeft radii.\n        ///\n        /// The corner radii default to [Radius.zero], i.e. right-angled corners.\n        public static RRect fromLTRBAndCorners(\n          double left,\n          double top,\n          double right,\n          double bottom,\n          Radius topLeft = null,\n          Radius topRight = null,\n          Radius bottomRight = null,\n          Radius bottomLeft = null)\n        {\n            if (topLeft == null)\n                topLeft = Radius.zero;\n\n            if (topRight == null)\n                topRight = Radius.zero;\n\n            if (bottomRight == null)\n                bottomRight = Radius.zero;\n\n            if (bottomLeft == null)\n                bottomLeft = Radius.zero;\n\n\n            var list = new List<double>(_kDataSize)\n            {\n               left,\n              top,\n              right,\n              bottom,\n              topLeft.x,\n              topLeft.y,\n              topRight.x,\n              topRight.y,\n              bottomRight.x,\n              bottomRight.y,\n              bottomLeft.x,\n              bottomLeft.y\n        };\n            return new RRect(list);\n        }\n\n        /// Construct a rounded rectangle from its bounding box and and topLeft,\n        /// topRight, bottomRight, and bottomLeft radii.\n        ///\n        /// The corner radii default to [Radius.zero], i.e. right-angled corners\n        public static RRect fromRectAndCorners(\n          Rect rect,\n            Radius topLeft = null,\n          Radius topRight = null,\n          Radius bottomRight = null,\n          Radius bottomLeft = null)\n        {\n            if (topLeft == null)\n                topLeft = Radius.zero;\n\n            if (topRight == null)\n                topRight = Radius.zero;\n\n            if (bottomRight == null)\n                bottomRight = Radius.zero;\n\n            if (bottomLeft == null)\n                bottomLeft = Radius.zero;\n            var list = new List<double>(_kDataSize)\n            {\n                rect.left,\n                rect.top,\n                rect.right,\n                rect.bottom,\n                topLeft.x,\n                topLeft.y,\n                topRight.x,\n                topRight.y,\n                bottomRight.x,\n                bottomRight.y,\n                bottomLeft.x,\n                bottomLeft.y\n            };\n            return new RRect(list);\n        }\n\n        static RRect _fromList(List<double> list)\n        {\n            var value = new List<double>(_kDataSize);\n            for (int i = 0; i < _kDataSize; i += 1)\n                value[i] = list[i];\n\n            return new RRect(value);\n        }\n\n        const int _kDataSize = 12;\n        public readonly List<double> _value = new List<double>(_kDataSize);\n        RRect _scaled; // same RRect with scaled radii per side\n\n        /// The offset of the left edge of this rectangle from the x axis.\n        public double left => _value[0];\n\n        /// The offset of the top edge of this rectangle from the y axis.\n        public double top => _value[1];\n\n        /// The offset of the right edge of this rectangle from the x axis.\n        public double right => _value[2];\n\n        /// The offset of the bottom edge of this rectangle from the y axis.\n        public double bottom => _value[3];\n\n        /// The top-left horizontal radius.\n        public double tlRadiusX => _value[4];\n\n        /// The top-left vertical radius.\n        public double tlRadiusY => _value[5];\n\n        /// The top-left [Radius].\n        public Radius tlRadius => Radius.elliptical(_value[4], _value[5]);\n\n        /// The top-right horizontal radius.\n        public double trRadiusX => _value[6];\n\n        /// The top-right vertical radius.\n        public double trRadiusY => _value[7];\n\n        /// The top-right [Radius].\n        public Radius trRadius => Radius.elliptical(_value[6], _value[7]);\n\n        /// The bottom-right horizontal radius.\n        public double brRadiusX => _value[8];\n\n        /// The bottom-right vertical radius.\n        public double brRadiusY => _value[9];\n\n        /// The bottom-right [Radius].\n        public Radius brRadius => Radius.elliptical(_value[8], _value[9]);\n\n        /// The bottom-left horizontal radius.\n        public double blRadiusX => _value[10];\n\n        /// The bottom-left vertical radius.\n        public double blRadiusY => _value[11];\n\n        /// The bottom-left [Radius].\n        public Radius blRadius => Radius.elliptical(_value[10], _value[11]);\n\n        /// A rounded rectangle with all the values set to zero.\n        public static readonly RRect zero = new RRect(new List<double>(_kDataSize));\n\n        /// Returns a new [RRect] translated by the given offset.\n        public RRect shift(Offset offset)\n        {\n            return RRect.fromLTRBAndCorners(\n              _value[0] + offset.dx,\n              _value[1] + offset.dy,\n              _value[2] + offset.dx,\n              _value[3] + offset.dy,\n              topLeft: Radius.elliptical(\n                _value[4],\n                _value[5]\n              ),\n              topRight: Radius.elliptical(\n                _value[6],\n                _value[7]\n              ),\n              bottomRight: Radius.elliptical(\n                _value[8],\n                _value[9]\n              ),\n              bottomLeft: Radius.elliptical(\n                _value[10],\n                _value[11]\n              )\n            );\n        }\n\n        /// Returns a new [RRect] with edges and radii moved outwards by the given\n        /// delta.\n        public RRect inflate(double delta)\n        {\n            return RRect.fromLTRBAndCorners(\n              _value[0] - delta,\n              _value[1] - delta,\n              _value[2] + delta,\n              _value[3] + delta,\n              topLeft: Radius.elliptical(\n                _value[4] + delta,\n                _value[5] + delta\n              ),\n              topRight: Radius.elliptical(\n                _value[6] + delta,\n                _value[7] + delta\n              ),\n              bottomRight: Radius.elliptical(\n                _value[8] + delta,\n                _value[9] + delta\n              ),\n              bottomLeft: Radius.elliptical(\n                _value[10] + delta,\n                _value[11] + delta\n              )\n            );\n        }\n\n        /// Returns a new [RRect] with edges and radii moved inwards by the given delta.\n        public RRect deflate(double delta) => inflate(-delta);\n\n        /// The distance between the left and right edges of this rectangle.\n        public double width => right - left;\n\n        /// The distance between the top and bottom edges of this rectangle.\n        public double height => bottom - top;\n\n        /// The bounding box of this rounded rectangle (the rectangle with no rounded corners).\n        public Rect outerRect => Rect.fromLTRB(left, top, right, bottom);\n\n        /// The non-rounded rectangle that is constrained by the smaller of the two\n        /// diagonals, with each diagonal traveling through the middle of the curve\n        /// corners. The middle of a corner is the intersection of the curve with its\n        /// respective quadrant bisector.\n        public Rect safeInnerRect\n        {\n            get\n            {\n                const double kInsetFactor = 0.29289321881; // 1-cos(pi/4)\n\n                double leftRadius = Math.Max(blRadiusX, tlRadiusX);\n                double topRadius = Math.Max(tlRadiusY, trRadiusY);\n                double rightRadius = Math.Max(trRadiusX, brRadiusX);\n                double bottomRadius = Math.Max(brRadiusY, blRadiusY);\n\n                return Rect.fromLTRB(\n                  left + leftRadius * kInsetFactor,\n                  top + topRadius * kInsetFactor,\n                  right - rightRadius * kInsetFactor,\n                  bottom - bottomRadius * kInsetFactor\n                );\n            }\n        }\n        /// The rectangle that would be formed using the axis-aligned intersection of\n        /// the sides of the rectangle, i.e., the rectangle formed from the\n        /// inner-most centers of the ellipses that form the corners. This is the\n        /// intersection of the [wideMiddleRect] and the [tallMiddleRect]. If any of\n        /// the intersections are void, the resulting [Rect] will have negative width\n        /// or height.\n        public Rect middleRect\n        {\n            get\n            {\n                double leftRadius = Math.Max(blRadiusX, tlRadiusX);\n                double rightRadius = Math.Max(brRadiusX, trRadiusX);\n                double topRadius = Math.Max(tlRadiusY, trRadiusY);\n                double bottomRadius = Math.Max(brRadiusY, blRadiusY);\n                return Rect.fromLTRB(\n                  left + leftRadius,\n                  top + topRadius,\n                  right - rightRadius,\n                  bottom - bottomRadius\n                );\n            }\n        }\n\n        /// The biggest rectangle that is entirely inside the rounded rectangle and\n        /// has the full width of the rounded rectangle. If the rounded rectangle does\n        /// not have an axis-aligned intersection of its left and right side, the\n        /// resulting [Rect] will have negative width or height.\n        public Rect wideMiddleRect\n        {\n            get\n            {\n                double topRadius = Math.Max(tlRadiusY, trRadiusY);\n                double bottomRadius = Math.Max(brRadiusY, blRadiusY);\n                return Rect.fromLTRB(\n                  left,\n                  top + topRadius,\n                  right,\n                  bottom - bottomRadius\n                );\n            }\n        }\n\n        /// The biggest rectangle that is entirely inside the rounded rectangle and\n        /// has the full height of the rounded rectangle. If the rounded rectangle\n        /// does not have an axis-aligned intersection of its top and bottom side, the\n        /// resulting [Rect] will have negative width or height.\n        public Rect tallMiddleRect\n        {\n            get\n            {\n                double leftRadius = Math.Max(blRadiusX, tlRadiusX);\n                double rightRadius = Math.Max(trRadiusX, brRadiusX);\n                return Rect.fromLTRB(\n                  left + leftRadius,\n                  top,\n                  right - rightRadius,\n                  bottom\n                );\n            }\n        }\n\n        /// Whether this rounded rectangle encloses a non-zero area.\n        /// Negative areas are considered empty.\n        public bool isEmpty => left >= right || top >= bottom;\n\n        /// Whether all coordinates of this rounded rectangle are finite.\n        public bool isFinite => left.isFinite() && top.isFinite() && right.isFinite() && bottom.isFinite();\n\n        /// Whether this rounded rectangle is a simple rectangle with zero\n        /// corner radii.\n        public bool isRect => (tlRadiusX == 0.0 || tlRadiusY == 0.0) &&\n           (trRadiusX == 0.0 || trRadiusY == 0.0) &&\n           (blRadiusX == 0.0 || blRadiusY == 0.0) &&\n           (brRadiusX == 0.0 || brRadiusY == 0.0);\n\n\n        /// Whether this rounded rectangle has a side with no straight section.\n        public bool isStadium => tlRadius == trRadius\n        && trRadius == brRadius\n        && brRadius == blRadius\n        && (width <= 2.0 * tlRadiusX || height <= 2.0 * tlRadiusY);\n\n\n        /// Whether this rounded rectangle has no side with a straight section.\n        public bool isEllipse => tlRadius == trRadius\n        && trRadius == brRadius\n        && brRadius == blRadius\n        && width <= 2.0 * tlRadiusX\n        && height <= 2.0 * tlRadiusY;\n\n        /// Whether this rounded rectangle would draw as a circle.\n        public bool isCircle => width == height && isEllipse;\n\n        /// The lesser of the magnitudes of the [width] and the [height] of this\n        /// rounded rectangle.\n        public double shortestSide => Math.Min(width.abs(), height.abs());\n\n        /// The greater of the magnitudes of the [width] and the [height] of this\n        /// rounded rectangle.\n        public double longestSide => Math.Max(width.abs(), height.abs());\n\n\n        /// The offset to the point halfway between the left and right and the top and\n        /// bottom edges of this rectangle.\n        public Offset center => new Offset(left + width / 2.0, top + height / 2.0);\n\n        // Returns the minimum between min and scale to which radius1 and radius2\n        // should be scaled with in order not to exceed the limit.\n        double _getMin(double min, double radius1, double radius2, double limit)\n        {\n            double sum = radius1 + radius2;\n            if (sum > limit && sum != 0.0)\n                return Math.Min(min, limit / sum);\n            return min;\n        }\n\n        // Scales all radii so that on each side their sum will not pass the size of\n        // the width/height.\n        //\n        // Inspired from:\n        //   https://github.com/google/skia/blob/master/src/core/SkRRect.cpp#L164\n        void _scaleRadii()\n        {\n            if (_scaled == null)\n            {\n                double scale = 1.0;\n                List<double> scaled = new List<double>(_value);\n\n                scale = _getMin(scale, scaled[11], scaled[5], height);\n                scale = _getMin(scale, scaled[4], scaled[6], width);\n                scale = _getMin(scale, scaled[7], scaled[9], height);\n                scale = _getMin(scale, scaled[8], scaled[10], width);\n\n                if (scale < 1.0)\n                {\n                    for (int i = 4; i < _kDataSize; i += 1)\n                        scaled[i] *= scale;\n                }\n\n                _scaled = RRect._fromList(scaled);\n            }\n        }\n\n        /// Whether the point specified by the given offset (which is assumed to be\n        /// relative to the origin) lies inside the rounded rectangle.\n        ///\n        /// This method may allocate (and cache) a copy of the object with normalized\n        /// radii the first time it is called on a particular [RRect] instance. When\n        /// using this method, prefer to reuse existing [RRect]s rather than\n        /// recreating the object each time.\n        public bool contains(Offset point)\n        {\n            if (point.dx < left || point.dx >= right || point.dy < top || point.dy >= bottom)\n                return false; // outside bounding box\n\n            _scaleRadii();\n\n            double x;\n            double y;\n            double radiusX;\n            double radiusY;\n            // check whether point is in one of the rounded corner areas\n            // x, y -> translate to ellipse center\n            if (point.dx < left + _scaled.tlRadiusX &&\n                point.dy < top + _scaled.tlRadiusY)\n            {\n                x = point.dx - left - _scaled.tlRadiusX;\n                y = point.dy - top - _scaled.tlRadiusY;\n                radiusX = _scaled.tlRadiusX;\n                radiusY = _scaled.tlRadiusY;\n            }\n            else if (point.dx > right - _scaled.trRadiusX &&\n                     point.dy < top + _scaled.trRadiusY)\n            {\n                x = point.dx - right + _scaled.trRadiusX;\n                y = point.dy - top - _scaled.trRadiusY;\n                radiusX = _scaled.trRadiusX;\n                radiusY = _scaled.trRadiusY;\n            }\n            else if (point.dx > right - _scaled.brRadiusX &&\n                     point.dy > bottom - _scaled.brRadiusY)\n            {\n                x = point.dx - right + _scaled.brRadiusX;\n                y = point.dy - bottom + _scaled.brRadiusY;\n                radiusX = _scaled.brRadiusX;\n                radiusY = _scaled.brRadiusY;\n            }\n            else if (point.dx < left + _scaled.blRadiusX &&\n                     point.dy > bottom - _scaled.blRadiusY)\n            {\n                x = point.dx - left - _scaled.blRadiusX;\n                y = point.dy - bottom + _scaled.blRadiusY;\n                radiusX = _scaled.blRadiusX;\n                radiusY = _scaled.blRadiusY;\n            }\n            else\n            {\n                return true; // inside and not within the rounded corner area\n            }\n\n            x = x / radiusX;\n            y = y / radiusY;\n            // check if the point is outside the unit circle\n            if (x * x + y * y > 1.0)\n                return false;\n            return true;\n        }\n\n        /// Linearly interpolate between two rounded rectangles.\n        ///\n        /// If either is null, this function substitutes [RRect.zero] instead.\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static RRect lerp(RRect a, RRect b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n            {\n                return _fromList(new List<double> {\n                  b.left * t,\n                  b.top * t,\n                  b.right * t,\n                  b.bottom * t,\n                  b.tlRadiusX * t,\n                  b.tlRadiusY * t,\n                  b.trRadiusX * t,\n                  b.trRadiusY * t,\n                  b.brRadiusX * t,\n                  b.brRadiusY * t,\n                  b.blRadiusX * t,\n                  b.blRadiusY * t});\n            }\n            if (b == null)\n            {\n                double k = 1.0 - t;\n                return _fromList(new List<double> {\n                  a.left * k,\n                  a.top * k,\n                  a.right * k,\n                  a.bottom * k,\n                  a.tlRadiusX * k,\n                  a.tlRadiusY * k,\n                  a.trRadiusX * k,\n                  a.trRadiusY * k,\n                  a.brRadiusX * k,\n                  a.brRadiusY * k,\n                  a.blRadiusX * k,\n                  a.blRadiusY * k});\n            }\n            return RRect._fromList(new List<double> {\n          lerpDouble(a.left, b.left, t),\n          lerpDouble(a.top, b.top, t),\n          lerpDouble(a.right, b.right, t),\n          lerpDouble(a.bottom, b.bottom, t),\n          lerpDouble(a.tlRadiusX, b.tlRadiusX, t),\n          lerpDouble(a.tlRadiusY, b.tlRadiusY, t),\n          lerpDouble(a.trRadiusX, b.trRadiusX, t),\n          lerpDouble(a.trRadiusY, b.trRadiusY, t),\n          lerpDouble(a.brRadiusX, b.brRadiusX, t),\n          lerpDouble(a.brRadiusY, b.brRadiusY, t),\n          lerpDouble(a.blRadiusX, b.blRadiusX, t),\n          lerpDouble(a.blRadiusY, b.blRadiusY, t)});\n        }\n\n        public static bool operator ==(RRect rrect, Object other)\n        {\n            if (identical(rrect, other))\n                return true;\n            if (rrect.GetType() != other.GetType())\n                return false;\n            RRect typedOther = (RRect)other;\n            for (int i = 0; i < _kDataSize; i += 1)\n            {\n                if (rrect._value[i] != typedOther._value[i])\n                    return false;\n            }\n            return true;\n        }\n\n        public static bool operator !=(RRect rrect, Object other) => !(rrect == other);\n\n        public int hashCode => hashList(_value);\n\n        public String toString()\n        {\n            String rect = $\"{left.toStringAsFixed(1)}, \" +\n                                $\"{top.toStringAsFixed(1)}, \" +\n                                $\"{right.toStringAsFixed(1)}, \" +\n                                $\"{bottom.toStringAsFixed(1)}\";\n            if (tlRadius == trRadius &&\n                trRadius == brRadius &&\n                brRadius == blRadius)\n            {\n                if (tlRadius.x == tlRadius.y)\n                    return $\"RRect.fromLTRBR({rect}, {tlRadius.x.toStringAsFixed(1)})\";\n                return $\"RRect.fromLTRBXY({rect}, {tlRadius.x.toStringAsFixed(1)}, {tlRadius.y.toStringAsFixed(1)})\";\n            }\n            return \"RRect.fromLTRBAndCorners(\" +\n                     $\"{rect}, \" +\n                     $\"topLeft: {tlRadius}, \" +\n                     $\"topRight: {trRadius}, \" +\n                     $\"bottomRight: {brRadius}, \" +\n                     $\"bottomLeft: {blRadius}\" +\n                   \")\";\n        }\n    }\n\n    /// A transform consisting of a translation, a rotation, and a uniform scale.\n    ///\n    /// Used by [Canvas.drawAtlas]. This is a more efficient way to represent these\n    /// simple transformations than a full matrix.\n    // Modeled after Skia's SkRSXform.\n    public class RSTransform\n    {\n        /// Creates an RSTransform.\n        ///\n        /// An [RSTransform] expresses the combination of a translation, a rotation\n        /// around a particular point, and a scale factor.\n        ///\n        /// The first argument, `scos`, is the cosine of the rotation, multiplied by\n        /// the scale factor.\n        ///\n        /// The second argument, `ssin`, is the sine of the rotation, multiplied by\n        /// that same scale factor.\n        ///\n        /// The third argument is the x coordinate of the translation, minus the\n        /// `scos` argument multiplied by the x-coordinate of the rotation point, plus\n        /// the `ssin` argument multiplied by the y-coordinate of the rotation point.\n        ///\n        /// The fourth argument is the y coordinate of the translation, minus the `ssin`\n        /// argument multiplied by the x-coordinate of the rotation point, minus the\n        /// `scos` argument multiplied by the y-coordinate of the rotation point.\n        ///\n        /// The [new RSTransform.fromComponents] method may be a simpler way to\n        /// construct these values. However, if there is a way to factor out the\n        /// computations of the sine and cosine of the rotation so that they can be\n        /// reused over multiple calls to this constructor, it may be more efficient\n        /// to directly use this constructor instead.\n        RSTransform(double scos, double ssin, double tx, double ty)\n        {\n            _value[0] = scos;\n            _value[1] = ssin;\n            _value[2] = tx;\n            _value[3] = ty;\n        }\n\n        /// Creates an RSTransform from its individual components.\n        ///\n        /// The `rotation` parameter gives the rotation in radians.\n        ///\n        /// The `scale` parameter describes the uniform scale factor.\n        ///\n        /// The `anchorX` and `anchorY` parameters give the coordinate of the point\n        /// around which to rotate.\n        ///\n        /// The `translateX` and `translateY` parameters give the coordinate of the\n        /// offset by which to translate.\n        ///\n        /// This constructor computes the arguments of the [new RSTransform]\n        /// constructor and then defers to that constructor to actually create the\n        /// object. If many [RSTransform] objects are being created and there is a way\n        /// to factor out the computations of the sine and cosine of the rotation\n        /// (which are computed each time this constructor is called) and reuse them\n        /// over multiple [RSTransform] objects, it may be more efficient to directly\n        /// use the more direct [new RSTransform] constructor instead.\n        public static RSTransform fromComponents(double rotation = 0.0,\n          double scale = 0.0,\n          double anchorX = 0.0,\n          double anchorY = 0.0,\n          double translateX = 0.0,\n          double translateY = 0.0\n        )\n        {\n            double scos = Math.Cos(rotation) * scale;\n            double ssin = Math.Sin(rotation) * scale;\n            double tx = translateX + -scos * anchorX + ssin * anchorY;\n            double ty = translateY + -ssin * anchorX - scos * anchorY;\n            return new RSTransform(scos, ssin, tx, ty);\n        }\n\n        readonly List<double> _value = new List<double>(4);\n\n        /// The cosine of the rotation multiplied by the scale factor.\n        public double scos => _value[0];\n\n        /// The sine of the rotation multiplied by that same scale factor.\n        public double ssin => _value[1];\n\n        /// The x coordinate of the translation, minus [scos] multiplied by the\n        /// x-coordinate of the rotation point, plus [ssin] multiplied by the\n        /// y-coordinate of the rotation point.\n        public double tx => _value[2];\n\n        /// The y coordinate of the translation, minus [ssin] multiplied by the\n        /// x-coordinate of the rotation point, minus [scos] multiplied by the\n        /// y-coordinate of the rotation point.\n        public double ty => _value[3];\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Hooks.cs",
    "content": "﻿using Newtonsoft.Json;\nusing System;\nusing System.Collections.Generic;\nusing static FlutterBinding.Mapping.Helper;\nusing static FlutterBinding.Mapping.Types;\nusing static FlutterBinding.UI.Painting;\n\nnamespace FlutterBinding.UI\n{\n    public static class Hooks\n    {      \n        static void _updateWindowMetrics(double devicePixelRatio,\n                                  double width,\n                                  double height,\n                                  double paddingTop,\n                                  double paddingRight,\n                                  double paddingBottom,\n                                  double paddingLeft,\n                                  double viewInsetTop,\n                                  double viewInsetRight,\n                                  double viewInsetBottom,\n                                  double viewInsetLeft)\n        {\n            var window = Window.Instance;\n            window.devicePixelRatio = devicePixelRatio;\n            window.physicalSize = new Size(width, height);\n            window.padding = new WindowPadding(\n                top: paddingTop,\n                right: paddingRight,\n                bottom: paddingBottom,\n                left: paddingLeft);\n            window.viewInsets = new WindowPadding(\n                top: viewInsetTop,\n                right: viewInsetRight,\n                bottom: viewInsetBottom,\n                left: viewInsetLeft);\n            _invoke(Window.Instance.onMetricsChanged, Window.Instance._onMetricsChangedZone);\n        }\n\n        delegate string _LocaleClosure();\n\n        static String _localeClosure() => Window.Instance.locale.toString();\n\n        static _LocaleClosure _getLocaleClosure() => _localeClosure;\n\n        static void _updateLocales(List<String> locales)\n        {\n            const int stringsPerLocale = 4;\n            int numLocales = (int)Math.Truncate((double)locales.Count / stringsPerLocale);\n            Window.Instance.locales = new List<Locale>(numLocales);\n            for (int localeIndex = 0; localeIndex < numLocales; localeIndex++)\n            {\n                Window.Instance.locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale],\n                                               locales[localeIndex * stringsPerLocale + 1]);\n            }\n            _invoke(Window.Instance.onLocaleChanged, Window.Instance._onLocaleChangedZone);\n        }\n\n        static void _updateUserSettingsData(String jsonData)\n        {\n            Dictionary<String, Object> data = JsonConvert.DeserializeObject<Dictionary<String, Object>>(jsonData);\n            _updateTextScaleFactor(Convert.ToDouble(data[\"textScaleFactor\"]));\n            _updateAlwaysUse24HourFormat(Convert.ToBoolean(data[\"alwaysUse24HourFormat\"]));\n        }\n\n        static void _updateTextScaleFactor(double textScaleFactor)\n        {\n            Window.Instance.textScaleFactor = textScaleFactor;\n            _invoke(Window.Instance.onTextScaleFactorChanged, Window.Instance._onTextScaleFactorChangedZone);\n        }\n\n        static void _updateAlwaysUse24HourFormat(bool alwaysUse24HourFormat)\n        {\n            Window.Instance.alwaysUse24HourFormat = alwaysUse24HourFormat;\n        }\n\n        static void _updateSemanticsEnabled(bool enabled)\n        {\n            Window.Instance.semanticsEnabled = enabled;\n            _invoke(Window.Instance.onSemanticsEnabledChanged, Window.Instance._onSemanticsEnabledChangedZone);\n        }\n\n        static void _updateAccessibilityFeatures(int values)\n        {\n            AccessibilityFeatures newFeatures = new AccessibilityFeatures(values);\n            if (newFeatures == Window.Instance.accessibilityFeatures)\n                return;\n            Window.Instance.accessibilityFeatures = newFeatures;\n            _invoke(Window.Instance.onAccessibilityFeaturesChanged, Window.Instance._onAccessibilityFlagsChangedZone);\n        }\n\n        static void _dispatchPlatformMessage(String name, ByteData data, int responseId)\n        {\n            if (Window.Instance.onPlatformMessage != null)\n            {\n                _invoke3<String, ByteData, PlatformMessageResponseCallback>(\n                 (a, b, c) => Window.Instance.onPlatformMessage(a, b, c),\n                  Window.Instance._onPlatformMessageZone,\n                  name,\n                  data,\n                  (ByteData responseData) =>\n                  {\n                      Window.Instance._respondToPlatformMessage(responseId, responseData);\n                  });\n            }\n            else\n            {\n                Window.Instance._respondToPlatformMessage(responseId, null);\n            }\n        }\n\n        static void _dispatchPointerDataPacket(ByteData packet)\n        {\n            if (Window.Instance.onPointerDataPacket != null)\n                _invoke1<PointerDataPacket>((d) => Window.Instance.onPointerDataPacket(d), Window.Instance._onPointerDataPacketZone, _unpackPointerDataPacket(packet));\n        }\n\n        static void _dispatchSemanticsAction(int id, int action, ByteData args)\n        {\n            _invoke3<int, SemanticsAction, ByteData>(\n             (a, b, c) => Window.Instance.onSemanticsAction(a, b, c),\n              Window.Instance._onSemanticsActionZone,\n              id,\n              SemanticsAction.values[action],\n              args);\n        }\n\n        static void _beginFrame(int microseconds)\n        {\n            _invoke1<Duration>((d) => Window.Instance.onBeginFrame(d), Window.Instance._onBeginFrameZone, new Duration(microseconds: microseconds));\n        }\n\n        static void _drawFrame()\n        {\n            _invoke(Window.Instance.onDrawFrame, Window.Instance._onDrawFrameZone);\n        }\n\n        /// Invokes [callback] inside the given [zone].\n        static void _invoke(VoidCallback callback, Zone zone)\n        {\n            if (callback == null)\n                return;\n\n            //assert(zone != null);\n\n            if (identical(zone, Zone.current))\n            {\n                callback();\n            }\n            else\n            {\n                zone.runGuarded(callback);\n            }\n        }\n\n        /// Invokes [callback] inside the given [zone] passing it [arg].\n        static void _invoke1<A>(Action<A> callback, Zone zone, A arg)\n        {\n            if (callback == null)\n                return;\n            \n            if (identical(zone, Zone.current))\n            {\n                callback(arg);\n            }\n            else\n            {\n                zone.runUnaryGuarded<A>(callback, arg);\n            }\n        }\n\n        /// Invokes [callback] inside the given [zone] passing it [arg1] and [arg2].\n        static void _invoke2<A1, A2>(Action<A1, A2> callback, Zone zone, A1 arg1, A2 arg2)\n        {\n            if (callback == null)\n                return;\n            \n            if (identical(zone, Zone.current))\n            {\n                callback(arg1, arg2);\n            }\n            else\n            {\n                zone.runBinaryGuarded<A1, A2>(callback, arg1, arg2);\n            }\n        }\n\n        /// Invokes [callback] inside the given [zone] passing it [arg1], [arg2] and [arg3].\n        static void _invoke3<A1, A2, A3>(Action<A1, A2, A3> callback, Zone zone, A1 arg1, A2 arg2, A3 arg3)\n        {\n            if (callback == null)\n                return;\n\n            if (identical(zone, Zone.current))\n            {\n                callback(arg1, arg2, arg3);\n            }\n            else\n            {\n                zone.runGuarded(() =>\n                {\n                    callback(arg1, arg2, arg3);\n                });\n            }\n        }\n\n        // If this value changes, update the encoding code in the following files:\n        //\n        //  * pointer_data.cc\n        //  * FlutterView.java\n        const int _kPointerDataFieldCount = 19;\n\n        static PointerDataPacket _unpackPointerDataPacket(ByteData packet)\n        {\n            const int kStride = 8; // Its an 8 const anyway - Int64List.bytesPerElement;\n            const int kBytesPerPointerData = _kPointerDataFieldCount * kStride;\n            int length = packet.lengthInBytes / kBytesPerPointerData;\n            List<PointerData> data = new List<PointerData>(length);\n            for (int i = 0; i < length; ++i)\n            {\n                int offset = i * _kPointerDataFieldCount;\n                data[i] = new PointerData(\n                  timeStamp: new Duration(microseconds: packet.getInt64(kStride * offset++, (int)_kFakeHostEndian)),\n                  change: (PointerChange)packet.getInt64(kStride * offset++, (int)_kFakeHostEndian),\n                  kind: (PointerDeviceKind)packet.getInt64(kStride * offset++, (int)_kFakeHostEndian),\n                  device: packet.getInt64(kStride * offset++, (int)_kFakeHostEndian),\n                  physicalX: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  physicalY: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  buttons: packet.getInt64(kStride * offset++, (int)_kFakeHostEndian),\n                  obscured: packet.getInt64(kStride * offset++, (int)_kFakeHostEndian) != 0,\n                  pressure: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  pressureMin: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  pressureMax: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  distance: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  distanceMax: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  radiusMajor: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  radiusMinor: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  radiusMin: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  radiusMax: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  orientation: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian),\n                  tilt: packet.getFloat64(kStride * offset++, (int)_kFakeHostEndian)\n                );\n            }\n            return new PointerDataPacket(data: data);\n        }\n    }\n}"
  },
  {
    "path": "FlutterBinding/UI/ICanvas.cs",
    "content": "﻿using System.Collections.Generic;\nusing SkiaSharp;\n\nnamespace FlutterBinding.UI\n{\n    public interface ICanvas\n    {\n        void ClipPath(Path path, bool doAntiAlias = true);\n        void ClipRect(Rect rect, ClipOp clipOp = default(ClipOp), bool doAntiAlias = true);\n        void ClipRRect(RRect rrect, bool doAntiAlias = true);\n        void DrawColor(Color color, BlendMode blendMode);\n        void DrawImageNine(SKImage image, Rect center, Rect dst, SKPaint paint);\n        void DrawLine(Offset p1, Offset p2, SKPaint paint);\n        void DrawPaint(SKPaint paint);\n        void DrawParagraph(Paragraph paragraph, Offset offset);\n        void DrawPicture(SKPicture picture);\n        void DrawPoints(PointMode pointMode, List<Offset> points, SKPaint paint);\n        void DrawRawAtlas(SKImage atlas, List<double> rstTransforms, List<double> rects, List<uint> colors, BlendMode blendMode, Rect cullRect, SKPaint paint);\n        void DrawRawPoints(PointMode pointMode, List<double> points, SKPaint paint);\n        void DrawShadow(Path path, Color color, double elevation, bool transparentOccluder);\n        void DrawVertices(SKVertices vertices, BlendMode blendMode, SKPaint paint);\n        int GetSaveCount();\n        void Restore();\n        void Rotate(double radians);\n        void Save();\n        void Scale(double sx, double sy = default(double));\n        void Skew(double sx, double sy);\n        void Transform(List<float> matrix4);\n        void Translate(double dx, double dy);\n    }\n}"
  },
  {
    "path": "FlutterBinding/UI/Lerp.cs",
    "content": "﻿namespace FlutterBinding.UI\n{\n    public static class Lerp\n    {\n        public static double lerpDouble(double a, double b, double t)\n        {\n            return a + (b - a) * t;\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/NativeFieldWrapperClass2.cs",
    "content": "﻿using FlutterBinding.Mapping;\nusing System;\n\nnamespace FlutterBinding.UI\n{\n    public class NativeFieldWrapperClass2\n    {\n\n        \n\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Painting.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing static FlutterBinding.Mapping.Types;\nusing static FlutterBinding.UI.Lerp;\nusing static FlutterBinding.Mapping.Helper;\nusing static FlutterBinding.UI.Helper;\nusing static FlutterBinding.UI.Painting;\nusing System.Linq;\nusing FlutterBinding.Mapping;\nusing System.Text;\nusing FlutterBinding.Engine.Painting;\nusing SkiaSharp;\n\nnamespace FlutterBinding.UI\n{\n\n    public static class Helper\n    {\n        public static SKPoint ToPoint(this Offset offset) => new SKPoint((float)offset.dx, (float)offset.dy);\n\n        public static List<SKPoint> ToPoints(this List<Offset> offset)\n        {\n            var list = new List<SKPoint>();\n            foreach (var point in offset)\n                list.Add(point.ToPoint());\n\n            return list;\n        }\n\n        public static List<SKColor> ToColors(this List<Color> colors)\n        {\n            var list = new List<SKColor>();\n\n            foreach (var color in colors)\n                list.Add(new SKColor(color.value));\n\n            return list;\n        }\n\n        public static SKRect ToRect(this Rect rect)\n            => new SKRect((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom);\n\n        public static SKRectI ToRectI(this Rect rect)\n            => new SKRectI((int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom);\n\n        public static SKRoundRect ToRoundedRect(this RRect rect)\n            => new SKRoundRect(new SKRect((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom), (float)rect.blRadiusX, (float)rect.blRadiusY);\n    }\n\n\n    public class Painting\n    {\n        // Some methods in this file assert that their arguments are not null. These\n        // asserts are just to improve the error messages; they should only cover\n        // arguments that are either dereferenced _in Dart_, before being passed to the\n        // engine, or that the engine explicitly null-checks itself (after attempting to\n        // convert the argument to a native type). It should not be possible for a null\n        // or invalid value to be used by the engine even in release mode, since that\n        // would cause a crash. It is, however, acceptable for error messages to be much\n        // less useful or correct in release mode than in debug mode.\n        //\n        // Painting APIs will also warn about arguments representing NaN coordinates,\n        // which can not be rendered by Skia.\n\n        // Update this list when changing the list of supported codecs.\n        /// {@template flutter.dart:ui.imageFormats}\n        /// JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP\n        /// {@endtemplate}\n\n        public static bool _rectIsValid(Rect rect)\n        {\n            //assert(rect != null, 'Rect argument was null.');\n            //assert(!rect._value.any((double value) => value.isNaN), 'Rect argument contained a NaN value.');\n            return true;\n        }\n\n        public static bool _rrectIsValid(RRect rrect)\n        {\n            //assert(rrect != null, 'RRect argument was null.');\n            //assert(!rrect._value.any((double value) => value.isNaN), 'RRect argument contained a NaN value.');\n            return true;\n        }\n\n        public static bool _offsetIsValid(Offset offset)\n        {\n            //assert(offset != null, 'Offset argument was null.');\n            //assert(!offset.dx.isNaN && !offset.dy.isNaN, 'Offset argument contained a NaN value.');\n            return true;\n        }\n\n        public static bool _matrix4IsValid(List<float> matrix4)\n        {\n            //assert(matrix4 != null, 'Matrix4 argument was null.');\n            //assert(matrix4.length == 16, 'Matrix4 must have 16 entries.');\n            return true;\n        }\n\n        public static bool _radiusIsValid(Radius radius)\n        {\n            //assert(radius != null, 'Radius argument was null.');\n            //assert(!radius.x.isNaN && !radius.y.isNaN, 'Radius argument contained a NaN value.');\n            return true;\n        }\n\n        public static Color _scaleAlpha(Color a, double factor)\n        {\n            return a.withAlpha((uint)(a.alpha * factor).round().clamp(0, 255));\n        }\n\n        public static List<uint> _encodeColorList(List<Color> colors)\n        {\n            int colorCount = colors.Count;\n            List<uint> result = new List<uint>(colorCount);\n            for (int i = 0; i < colorCount; ++i)\n                result[i] = colors[i].value;\n            return result;\n        }\n\n        public static List<double> _encodePointList(List<Offset> points)\n        {\n            //assert(points != null);\n            int pointCount = points.Count;\n            List<double> result = new List<double>(pointCount * 2);\n            for (int i = 0; i < pointCount; ++i)\n            {\n                int xIndex = i * 2;\n                int yIndex = xIndex + 1;\n                Offset point = points[i];\n                //assert(_offsetIsValid(point));\n                result[xIndex] = point.dx;\n                result[yIndex] = point.dy;\n            }\n            return result;\n        }\n\n        public static List<double> _encodeTwoPoints(Offset pointA, Offset pointB)\n        {\n            //assert(_offsetIsValid(pointA));\n            //assert(_offsetIsValid(pointB));\n            List<double> result = new List<double>(4);\n            result[0] = pointA.dx;\n            result[1] = pointA.dy;\n            result[2] = pointB.dx;\n            result[3] = pointB.dy;\n            return result;\n        }\n\n        /// The global default value of whether and how to clip a widget. This is only for\n        /// temporary migration from default-to-clip to default-to-NOT-clip.\n        ///\n        // TODO(liyuqian): Set it to Clip.none. (https://github.com/flutter/flutter/issues/18057)\n        // We currently have Clip.antiAlias to preserve our old behaviors.\n        [Obsolete(\"Do not use this as it'll soon be removed after we set the default behavior to Clip.none.\")]\n        public const Clip defaultClipBehavior = Clip.antiAlias;\n\n        // If we actually run on big endian machines, we'll need to do something smarter\n        // here. We don't use [Endian.Host] because it's not a compile-time\n        // constant and can't propagate into the set/get calls.\n        public const Endian _kFakeHostEndian = Endian.Little;\n\n        /// Instantiates an image codec [Codec] object.\n        ///\n        /// [list] is the binary image data (e.g a PNG or GIF binary data).\n        /// The data can be for either static or animated images. The following image\n        /// formats are supported: {@macro flutter.dart:ui.imageFormats}\n        ///\n        /// The [decodedCacheRatioCap] is the default maximum multiple of the compressed\n        /// image size to cache when decoding animated image frames. For example,\n        /// setting this to `2.0` means that a 400KB GIF would be allowed at most to use\n        /// 800KB of memory caching unessential decoded frames. Caching decoded frames\n        /// saves CPU but can result in out-of-memory crashes when decoding large (or\n        /// multiple) animated images. Note that GIFs are highly compressed, and it's\n        /// unlikely that a factor that low will be sufficient to cache all decoded\n        /// frames. The default value is `25.0`.\n        ///\n        /// The returned future can complete with an error if the image decoding has\n        /// failed.\n        public Task<SKCodec> instantiateImageCodec(List<int> list,\n            double decodedCacheRatioCap = double.PositiveInfinity)\n        {\n            return _futurize(\n              (_Callback<SKCodec> callback) => _instantiateImageCodec(list, callback, null, decodedCacheRatioCap));\n        }\n\n        /// Instantiates a [Codec] object for an image binary data.\n        ///\n        /// Returns an error message if the instantiation has failed, null otherwise.\n        String _instantiateImageCodec(List<int> list, _Callback<SKCodec> callback, _ImageInfo imageInfo, double decodedCacheRatioCap)\n            => NativeCodec.InstantiateImageCodec(list, callback, imageInfo, decodedCacheRatioCap);\n\n        /// Loads a single image frame from a byte array into an [Image] object.\n        ///\n        /// This is a convenience wrapper around [instantiateImageCodec].\n        /// Prefer using [instantiateImageCodec] which also supports multi frame images.\n        void decodeImageFromList(List<int> list, ImageDecoderCallback callback)\n        {\n            _decodeImageFromListAsync(list, callback);\n        }\n\n        async Task _decodeImageFromListAsync(List<int> list,\n                                           ImageDecoderCallback callback)\n        {\n            SKCodec codec = await instantiateImageCodec(list);\n            SKCodecFrameInfo frameInfo = codec.FrameInfo[0]; // TODO: .getNextFrame();\n            callback(frameInfo.GetImage(codec));\n        }\n\n        /// Convert an array of pixel values into an [Image] object.\n        ///\n        /// [pixels] is the pixel data in the encoding described by [format].\n        ///\n        /// [rowBytes] is the number of bytes consumed by each row of pixels in the\n        /// data buffer.  If unspecified, it defaults to [width] multipled by the\n        /// number of bytes per pixel in the provided [format].\n        ///\n        /// The [decodedCacheRatioCap] is the default maximum multiple of the compressed\n        /// image size to cache when decoding animated image frames. For example,\n        /// setting this to `2.0` means that a 400KB GIF would be allowed at most to use\n        /// 800KB of memory caching unessential decoded frames. Caching decoded frames\n        /// saves CPU but can result in out-of-memory crashes when decoding large (or\n        /// multiple) animated images. Note that GIFs are highly compressed, and it's\n        /// unlikely that a factor that low will be sufficient to cache all decoded\n        /// frames. The default value is `25.0`.\n        public void decodeImageFromPixels(\n          List<int> pixels,\n          int width,\n          int height,\n          PixelFormat format,\n          ImageDecoderCallback callback,\n          int rowBytes = 0, double decodedCacheRatioCap = double.PositiveInfinity)\n        {\n            _ImageInfo imageInfo = new _ImageInfo(width, height, (int)format, rowBytes);\n            Future<SKCodec> codecFuture = _futurize(\n              (_Callback<SKCodec> cb) => _instantiateImageCodec(pixels, cb, imageInfo, decodedCacheRatioCap)\n            );\n            codecFuture.ContinueWith(async (Task<SKCodec> codec) => callback(codec.Result.FrameInfo[0].GetImage(codec.Result)));\n        }\n\n    }\n\n    /// An immutable 32 bit color value in ARGB format.\n    ///\n    /// Consider the light teal of the Flutter logo. It is fully opaque, with a red\n    /// channel value of 0x42 (66), a green channel value of 0xA5 (165), and a blue\n    /// channel value of 0xF5 (245). In the common \"hash syntax\" for colour values,\n    /// it would be described as `#42A5F5`.\n    ///\n    /// Here are some ways it could be constructed:\n    ///\n    /// ```dart\n    /// Color c = const Color(0xFF42A5F5);\n    /// Color c = const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5);\n    /// Color c = const Color.fromARGB(255, 66, 165, 245);\n    /// Color c = const Color.fromRGBO(66, 165, 245, 1.0);\n    /// ```\n    ///\n    /// If you are having a problem with `Color` wherein it seems your color is just\n    /// not painting, check to make sure you are specifying the full 8 hexadecimal\n    /// digits. If you only specify six, then the leading two digits are assumed to\n    /// be zero, which means fully-transparent:\n    ///\n    /// ```dart\n    /// Color c1 = const Color(0xFFFFFF); // fully transparent white (invisible)\n    /// Color c2 = const Color(0xFFFFFFFF); // fully opaque white (visible)\n    /// ```\n    ///\n    /// See also:\n    ///\n    ///  * [Colors](https://docs.flutter.io/flutter/material/Colors-class.html), which\n    ///    defines the colors found in the Material Design specification.\n    public class Color\n    {\n        /// Construct a color from the lower 32 bits of an [int].\n        ///\n        /// The bits are interpreted as follows:\n        ///\n        /// * Bits 24-31 are the alpha value.\n        /// * Bits 16-23 are the red value.\n        /// * Bits 8-15 are the green value.\n        /// * Bits 0-7 are the blue value.\n        ///\n        /// In other words, if AA is the alpha value in hex, RR the red value in hex,\n        /// GG the green value in hex, and BB the blue value in hex, a color can be\n        /// expressed as `const Color(0xAARRGGBB)`.\n        ///\n        /// For example, to get a fully opaque orange, you would use `const\n        /// Color(0xFFFF9000)` (`FF` for the alpha, `FF` for the red, `90` for the\n        /// green, and `00` for the blue).\n        // //@pragma('vm:entry-point')\n        public Color(uint value)\n        {\n            this.value = value & 0xFFFFFFFF;\n        }\n\n        /// Construct a color from the lower 8 bits of four integers.\n        ///\n        /// * `a` is the alpha value, with 0 being transparent and 255 being fully\n        ///   opaque.\n        /// * `r` is [red], from 0 to 255.\n        /// * `g` is [green], from 0 to 255.\n        /// * `b` is [blue], from 0 to 255.\n        ///\n        /// Out of range values are brought into range using modulo 255.\n        ///\n        /// See also [fromRGBO], which takes the alpha value as a floating point\n        /// value.\n        public static Color fromARGB(uint a, uint r, uint g, uint b)\n        {\n            var value = (((a & 0xff) << 24) |\n                     ((r & 0xff) << 16) |\n                     ((g & 0xff) << 8) |\n                     ((b & 0xff) << 0)) & 0xFFFFFFFF;\n            return new Color(value);\n        }\n\n        /// Create a color from red, green, blue, and opacity, similar to `rgba()` in CSS.\n        ///\n        /// * `r` is [red], from 0 to 255.\n        /// * `g` is [green], from 0 to 255.\n        /// * `b` is [blue], from 0 to 255.\n        /// * `opacity` is alpha channel of this color as a double, with 0.0 being\n        ///   transparent and 1.0 being fully opaque.\n        ///\n        /// Out of range values are brought into range using modulo 255.\n        ///\n        /// See also [fromARGB], which takes the opacity as an integer value.\n        public static Color fromRGBO(int r, int g, int b, double opacity)\n        {\n            var value = (uint)((((int)Math.Truncate(opacity * 0xff / 1.0) & 0xff) << 24) |\n                      ((r & 0xff) << 16) |\n                      ((g & 0xff) << 8) |\n                      ((b & 0xff) << 0)) & 0xFFFFFFFF;\n\n            return new Color(value);\n        }\n        /// A 32 bit value representing this color.\n        ///\n        /// The bits are assigned as follows:\n        ///\n        /// * Bits 24-31 are the alpha value.\n        /// * Bits 16-23 are the red value.\n        /// * Bits 8-15 are the green value.\n        /// * Bits 0-7 are the blue value.\n        public uint value;\n\n        /// The alpha channel of this color in an 8 bit value.\n        ///\n        /// A value of 0 means this color is fully transparent. A value of 255 means\n        /// this color is fully opaque.\n        public uint alpha => (0xff000000 & value) >> 24;\n\n        /// The alpha channel of this color as a double.\n        ///\n        /// A value of 0.0 means this color is fully transparent. A value of 1.0 means\n        /// this color is fully opaque.\n        public double opacity => alpha / 0xFF;\n\n        /// The red channel of this color in an 8 bit value.\n        public uint red => (0x00ff0000 & value) >> 16;\n\n        /// The green channel of this color in an 8 bit value.\n        public uint green => (0x0000ff00 & value) >> 8;\n\n        /// The blue channel of this color in an 8 bit value.\n        public uint blue => (0x000000ff & value) >> 0;\n\n        /// Returns a new color that matches this color with the alpha channel\n        /// replaced with `a` (which ranges from 0 to 255).\n        ///\n        /// Out of range values will have unexpected effects.\n        public Color withAlpha(uint a)\n        {\n            return Color.fromARGB(a, red, green, blue);\n        }\n\n        /// Returns a new color that matches this color with the alpha channel\n        /// replaced with the given `opacity` (which ranges from 0.0 to 1.0).\n        ///\n        /// Out of range values will have unexpected effects.\n        public Color withOpacity(double opacity)\n        {\n            //assert(opacity >= 0.0 && opacity <= 1.0);\n            return withAlpha((uint)(255.0 * opacity).round());\n        }\n\n        /// Returns a new color that matches this color with the red channel replaced\n        /// with `r` (which ranges from 0 to 255).\n        ///\n        /// Out of range values will have unexpected effects.\n        public Color withRed(uint r)\n        {\n            return Color.fromARGB(alpha, r, green, blue);\n        }\n\n        /// Returns a new color that matches this color with the green channel\n        /// replaced with `g` (which ranges from 0 to 255).\n        ///\n        /// Out of range values will have unexpected effects.\n        public Color withGreen(uint g)\n        {\n            return Color.fromARGB(alpha, red, g, blue);\n        }\n\n        /// Returns a new color that matches this color with the blue channel replaced\n        /// with `b` (which ranges from 0 to 255).\n        ///\n        /// Out of range values will have unexpected effects.\n        public Color withBlue(uint b)\n        {\n            return Color.fromARGB(alpha, red, green, b);\n        }\n\n        // See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>\n        static double _linearizeColorComponent(double component)\n        {\n            if (component <= 0.03928)\n                return component / 12.92;\n            return Math.Pow((component + 0.055) / 1.055, 2.4);\n        }\n\n        /// Returns a brightness value between 0 for darkest and 1 for lightest.\n        ///\n        /// Represents the relative luminance of the color. This value is computationally\n        /// expensive to calculate.\n        ///\n        /// See <https://en.wikipedia.org/wiki/Relative_luminance>.\n        public double computeLuminance()\n        {\n            // See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>\n            double R = _linearizeColorComponent(red / 0xFF);\n            double G = _linearizeColorComponent(green / 0xFF);\n            double B = _linearizeColorComponent(blue / 0xFF);\n            return 0.2126 * R + 0.7152 * G + 0.0722 * B;\n        }\n\n        /// Linearly interpolate between two colors.\n        ///\n        /// This is intended to be fast but as a result may be ugly. Consider\n        /// [HSVColor] or writing custom logic for interpolating colors.\n        ///\n        /// If either color is null, this function linearly interpolates from a\n        /// transparent instance of the other color. This is usually preferable to\n        /// interpolating from [material.Colors.transparent] (`const\n        /// Color(0x00000000)`), which is specifically transparent _black_.\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]). Each channel\n        /// will be clamped to the range 0 to 255.\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static Color lerp(Color a, Color b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return _scaleAlpha(b, t);\n            if (b == null)\n                return _scaleAlpha(a, 1.0 - t);\n            return Color.fromARGB(\n              (uint)lerpDouble(a.alpha, b.alpha, t).toInt().clamp(0, 255),\n              (uint)lerpDouble(a.red, b.red, t).toInt().clamp(0, 255),\n              (uint)lerpDouble(a.green, b.green, t).toInt().clamp(0, 255),\n              (uint)lerpDouble(a.blue, b.blue, t).toInt().clamp(0, 255));\n        }\n\n        /// Combine the foreground color as a transparent color over top\n        /// of a background color, and return the resulting combined color.\n        ///\n        /// This uses standard alpha blending (\"SRC over DST\") rules to produce a\n        /// blended color from two colors. This can be used as a performance\n        /// enhancement when trying to avoid needless alpha blending compositing\n        /// operations for two things that are solid colors with the same shape, but\n        /// overlay each other: instead, just paint one with the combined color.\n        static Color alphaBlend(Color foreground, Color background)\n        {\n            int alpha = (int)foreground.alpha;\n            if (alpha == 0x00)\n            { // Foreground completely transparent.\n                return background;\n            }\n            int invAlpha = 0xff - alpha;\n            int backAlpha = (int)background.alpha;\n            if (backAlpha == 0xff)\n            { // Opaque background case\n                return Color.fromARGB(\n                  0xff,\n                  (uint)((alpha * foreground.red + invAlpha * background.red) / 0xff),\n                  (uint)((alpha * foreground.green + invAlpha * background.green) / 0xff),\n                  (uint)((alpha * foreground.blue + invAlpha * background.blue) / 0xff));\n            }\n            else\n            { // General case\n                backAlpha = (backAlpha * invAlpha) / 0xff;\n                int outAlpha = alpha + backAlpha;\n                //assert(outAlpha != 0x00);\n                return Color.fromARGB(\n                  (uint)outAlpha,\n                  (uint)((foreground.red * alpha + background.red * backAlpha) / outAlpha),\n                  (uint)((foreground.green * alpha + background.green * backAlpha) / outAlpha),\n                  (uint)((foreground.blue * alpha + background.blue * backAlpha) / outAlpha));\n            }\n        }\n\n        public static bool operator ==(Color color, Object other)\n        {\n            if (identical(color, other))\n                return true;\n            if (other.GetType() != color.GetType())\n                return false;\n            Color typedOther = (Color)other;\n            return color.value == typedOther.value;\n        }\n\n        public static bool operator !=(Color color, Object other) => !(color == other);\n\n        public int hashCode => value.GetHashCode();\n\n        public String toString() => $\"Color(0x{value.toRadixString(16).PadLeft(8, '0')})\";\n    }\n\n    /// Algorithms to use when painting on the canvas.\n    ///\n    /// When drawing a shape or image onto a canvas, different algorithms can be\n    /// used to blend the pixels. The different values of [BlendMode] specify\n    /// different such algorithms.\n    ///\n    /// Each algorithm has two inputs, the _source_, which is the image being drawn,\n    /// and the _destination_, which is the image into which the source image is\n    /// being composited. The destination is often thought of as the _background_.\n    /// The source and destination both have four color channels, the red, green,\n    /// blue, and alpha channels. These are typically represented as numbers in the\n    /// range 0.0 to 1.0. The output of the algorithm also has these same four\n    /// channels, with values computed from the source and destination.\n    ///\n    /// The documentation of each value below describes how the algorithm works. In\n    /// each case, an image shows the output of blending a source image with a\n    /// destination image. In the images below, the destination is represented by an\n    /// image with horizontal lines and an opaque landscape photograph, and the\n    /// source is represented by an image with vertical lines (the same lines but\n    /// rotated) and a bird clip-art image. The [src] mode shows only the source\n    /// image, and the [dst] mode shows only the destination image. In the\n    /// documentation below, the transparency is illustrated by a checkerboard\n    /// pattern. The [clear] mode drops both the source and destination, resulting\n    /// in an output that is entirely transparent (illustrated by a solid\n    /// checkerboard pattern).\n    ///\n    /// The horizontal and vertical bars in these images show the red, green, and\n    /// blue channels with varying opacity levels, then all three color channels\n    /// together with those same varying opacity levels, then all three color\n    /// channels set to zero with those varying opacity levels, then two bars showing\n    /// a red/green/blue repeating gradient, the first with full opacity and the\n    /// second with partial opacity, and finally a bar with the three color channels\n    /// set to zero but the opacity varying in a repeating gradient.\n    ///\n    /// ## Application to the [Canvas] API\n    ///\n    /// When using [Canvas.saveLayer] and [Canvas.restore], the blend mode of the\n    /// [Paint] given to the [Canvas.saveLayer] will be applied when\n    /// [Canvas.restore] is called. Each call to [Canvas.saveLayer] introduces a new\n    /// layer onto which shapes and images are painted; when [Canvas.restore] is\n    /// called, that layer is then composited onto the parent layer, with the source\n    /// being the most-recently-drawn shapes and images, and the destination being\n    /// the parent layer. (For the first [Canvas.saveLayer] call, the parent layer\n    /// is the canvas itself.)\n    ///\n    /// See also:\n    ///\n    ///  * [Paint.blendMode], which uses [BlendMode] to define the compositing\n    ///    strategy.\n    public enum BlendMode\n    {\n        // This list comes from Skia's SkXfermode.h and the values (order) should be\n        // kept in sync.\n        // See: https://skia.org/user/api/skpaint#SkXfermode\n\n        /// Drop both the source and destination images, leaving nothing.\n        ///\n        /// This corresponds to the \"clear\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_clear.png)\n        clear,\n\n        /// Drop the destination image, only paint the source image.\n        ///\n        /// Conceptually, the destination is first cleared, then the source image is\n        /// painted.\n        ///\n        /// This corresponds to the \"Copy\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_src.png)\n        src,\n\n        /// Drop the source image, only paint the destination image.\n        ///\n        /// Conceptually, the source image is discarded, leaving the destination\n        /// untouched.\n        ///\n        /// This corresponds to the \"Destination\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dst.png)\n        dst,\n\n        /// Composite the source image over the destination image.\n        ///\n        /// This is the default value. It represents the most intuitive case, where\n        /// shapes are painted on top of what is below, with transparent areas showing\n        /// the destination layer.\n        ///\n        /// This corresponds to the \"Source over Destination\" Porter-Duff operator,\n        /// also known as the Painter's Algorithm.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcOver.png)\n        srcOver,\n\n        /// Composite the source image under the destination image.\n        ///\n        /// This is the opposite of [srcOver].\n        ///\n        /// This corresponds to the \"Destination over Source\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstOver.png)\n        ///\n        /// This is useful when the source image should have been painted before the\n        /// destination image, but could not be.\n        dstOver,\n\n        /// Show the source image, but only where the two images overlap. The\n        /// destination image is not rendered, it is treated merely as a mask. The\n        /// color channels of the destination are ignored, only the opacity has an\n        /// effect.\n        ///\n        /// To show the destination image instead, consider [dstIn].\n        ///\n        /// To reverse the semantic of the mask (only showing the source where the\n        /// destination is absent, rather than where it is present), consider\n        /// [srcOut].\n        ///\n        /// This corresponds to the \"Source in Destination\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcIn.png)\n        srcIn,\n\n        /// Show the destination image, but only where the two images overlap. The\n        /// source image is not rendered, it is treated merely as a mask. The color\n        /// channels of the source are ignored, only the opacity has an effect.\n        ///\n        /// To show the source image instead, consider [srcIn].\n        ///\n        /// To reverse the semantic of the mask (only showing the source where the\n        /// destination is present, rather than where it is absent), consider [dstOut].\n        ///\n        /// This corresponds to the \"Destination in Source\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstIn.png)\n        dstIn,\n\n        /// Show the source image, but only where the two images do not overlap. The\n        /// destination image is not rendered, it is treated merely as a mask. The color\n        /// channels of the destination are ignored, only the opacity has an effect.\n        ///\n        /// To show the destination image instead, consider [dstOut].\n        ///\n        /// To reverse the semantic of the mask (only showing the source where the\n        /// destination is present, rather than where it is absent), consider [srcIn].\n        ///\n        /// This corresponds to the \"Source out Destination\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcOut.png)\n        srcOut,\n\n        /// Show the destination image, but only where the two images do not overlap. The\n        /// source image is not rendered, it is treated merely as a mask. The color\n        /// channels of the source are ignored, only the opacity has an effect.\n        ///\n        /// To show the source image instead, consider [srcOut].\n        ///\n        /// To reverse the semantic of the mask (only showing the destination where the\n        /// source is present, rather than where it is absent), consider [dstIn].\n        ///\n        /// This corresponds to the \"Destination out Source\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstOut.png)\n        dstOut,\n\n        /// Composite the source image over the destination image, but only where it\n        /// overlaps the destination.\n        ///\n        /// This corresponds to the \"Source atop Destination\" Porter-Duff operator.\n        ///\n        /// This is essentially the [srcOver] operator, but with the output's opacity\n        /// channel being set to that of the destination image instead of being a\n        /// combination of both image's opacity channels.\n        ///\n        /// For a variant with the destination on top instead of the source, see\n        /// [dstATop].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_srcATop.png)\n        srcATop,\n\n        /// Composite the destination image over the source image, but only where it\n        /// overlaps the source.\n        ///\n        /// This corresponds to the \"Destination atop Source\" Porter-Duff operator.\n        ///\n        /// This is essentially the [dstOver] operator, but with the output's opacity\n        /// channel being set to that of the source image instead of being a\n        /// combination of both image's opacity channels.\n        ///\n        /// For a variant with the source on top instead of the destination, see\n        /// [srcATop].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_dstATop.png)\n        dstATop,\n\n        /// Apply a bitwise `xor` operator to the source and destination images. This\n        /// leaves transparency where they would overlap.\n        ///\n        /// This corresponds to the \"Source xor Destination\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_xor.png)\n        xor,\n\n        /// Sum the components of the source and destination images.\n        ///\n        /// Transparency in a pixel of one of the images reduces the contribution of\n        /// that image to the corresponding output pixel, as if the color of that\n        /// pixel in that image was darker.\n        ///\n        /// This corresponds to the \"Source plus Destination\" Porter-Duff operator.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_plus.png)\n        plus,\n\n        /// Multiply the color components of the source and destination images.\n        ///\n        /// This can only result in the same or darker colors (multiplying by white,\n        /// 1.0, results in no change; multiplying by black, 0.0, results in black).\n        ///\n        /// When compositing two opaque images, this has similar effect to overlapping\n        /// two transparencies on a projector.\n        ///\n        /// For a variant that also multiplies the alpha channel, consider [multiply].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_modulate.png)\n        ///\n        /// See also:\n        ///\n        ///  * [screen], which does a similar computation but inverted.\n        ///  * [overlay], which combines [modulate] and [screen] to favor the\n        ///    destination image.\n        ///  * [hardLight], which combines [modulate] and [screen] to favor the\n        ///    source image.\n        modulate,\n\n        // Following blend modes are defined in the CSS Compositing standard.\n\n        /// Multiply the inverse of the components of the source and destination\n        /// images, and inverse the result.\n        ///\n        /// Inverting the components means that a fully saturated channel (opaque\n        /// white) is treated as the value 0.0, and values normally treated as 0.0\n        /// (black, transparent) are treated as 1.0.\n        ///\n        /// This is essentially the same as [modulate] blend mode, but with the values\n        /// of the colors inverted before the multiplication and the result being\n        /// inverted back before rendering.\n        ///\n        /// This can only result in the same or lighter colors (multiplying by black,\n        /// 1.0, results in no change; multiplying by white, 0.0, results in white).\n        /// Similarly, in the alpha channel, it can only result in more opaque colors.\n        ///\n        /// This has similar effect to two projectors displaying their images on the\n        /// same screen simultaneously.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_screen.png)\n        ///\n        /// See also:\n        ///\n        ///  * [modulate], which does a similar computation but without inverting the\n        ///    values.\n        ///  * [overlay], which combines [modulate] and [screen] to favor the\n        ///    destination image.\n        ///  * [hardLight], which combines [modulate] and [screen] to favor the\n        ///    source image.\n        screen,  // The last coeff mode.\n\n        /// Multiply the components of the source and destination images after\n        /// adjusting them to favor the destination.\n        ///\n        /// Specifically, if the destination value is smaller, this multiplies it with\n        /// the source value, whereas is the source value is smaller, it multiplies\n        /// the inverse of the source value with the inverse of the destination value,\n        /// then inverts the result.\n        ///\n        /// Inverting the components means that a fully saturated channel (opaque\n        /// white) is treated as the value 0.0, and values normally treated as 0.0\n        /// (black, transparent) are treated as 1.0.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_overlay.png)\n        ///\n        /// See also:\n        ///\n        ///  * [modulate], which always multiplies the values.\n        ///  * [screen], which always multiplies the inverses of the values.\n        ///  * [hardLight], which is similar to [overlay] but favors the source image\n        ///    instead of the destination image.\n        overlay,\n\n        /// Composite the source and destination image by choosing the lowest value\n        /// from each color channel.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_darken.png)\n        darken,\n\n        /// Composite the source and destination image by choosing the highest value\n        /// from each color channel.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_lighten.png)\n        lighten,\n\n        /// Divide the destination by the inverse of the source.\n        ///\n        /// Inverting the components means that a fully saturated channel (opaque\n        /// white) is treated as the value 0.0, and values normally treated as 0.0\n        /// (black, transparent) are treated as 1.0.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_colorDodge.png)\n        colorDodge,\n\n        /// Divide the inverse of the destination by the the source, and inverse the result.\n        ///\n        /// Inverting the components means that a fully saturated channel (opaque\n        /// white) is treated as the value 0.0, and values normally treated as 0.0\n        /// (black, transparent) are treated as 1.0.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_colorBurn.png)\n        colorBurn,\n\n        /// Multiply the components of the source and destination images after\n        /// adjusting them to favor the source.\n        ///\n        /// Specifically, if the source value is smaller, this multiplies it with the\n        /// destination value, whereas is the destination value is smaller, it\n        /// multiplies the inverse of the destination value with the inverse of the\n        /// source value, then inverts the result.\n        ///\n        /// Inverting the components means that a fully saturated channel (opaque\n        /// white) is treated as the value 0.0, and values normally treated as 0.0\n        /// (black, transparent) are treated as 1.0.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hardLight.png)\n        ///\n        /// See also:\n        ///\n        ///  * [modulate], which always multiplies the values.\n        ///  * [screen], which always multiplies the inverses of the values.\n        ///  * [overlay], which is similar to [hardLight] but favors the destination\n        ///    image instead of the source image.\n        hardLight,\n\n        /// Use [colorDodge] for source values below 0.5 and [colorBurn] for source\n        /// values above 0.5.\n        ///\n        /// This results in a similar but softer effect than [overlay].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_softLight.png)\n        ///\n        /// See also:\n        ///\n        ///  * [color], which is a more subtle tinting effect.\n        softLight,\n\n        /// Subtract the smaller value from the bigger value for each channel.\n        ///\n        /// Compositing black has no effect; compositing white inverts the colors of\n        /// the other image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver].\n        ///\n        /// The effect is similar to [exclusion] but harsher.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_difference.png)\n        difference,\n\n        /// Subtract double the product of the two images from the sum of the two\n        /// images.\n        ///\n        /// Compositing black has no effect; compositing white inverts the colors of\n        /// the other image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver].\n        ///\n        /// The effect is similar to [difference] but softer.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_exclusion.png)\n        exclusion,\n\n        /// Multiply the components of the source and destination images, including\n        /// the alpha channel.\n        ///\n        /// This can only result in the same or darker colors (multiplying by white,\n        /// 1.0, results in no change; multiplying by black, 0.0, results in black).\n        ///\n        /// Since the alpha channel is also multiplied, a fully-transparent pixel\n        /// (opacity 0.0) in one image results in a fully transparent pixel in the\n        /// output. This is similar to [dstIn], but with the colors combined.\n        ///\n        /// For a variant that multiplies the colors but does not multiply the alpha\n        /// channel, consider [modulate].\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_multiply.png)\n        multiply,  // The last separable mode.\n\n        /// Take the hue of the source image, and the saturation and luminosity of the\n        /// destination image.\n        ///\n        /// The effect is to tint the destination image with the source image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver]. Regions that are entirely transparent in the source image take\n        /// their hue from the destination.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hue.png)\n        ///\n        /// See also:\n        ///\n        ///  * [color], which is a similar but stronger effect as it also applies the\n        ///    saturation of the source image.\n        ///  * [HSVColor], which allows colors to be expressed using Hue rather than\n        ///    the red/green/blue channels of [Color].\n        hue,\n\n        /// Take the saturation of the source image, and the hue and luminosity of the\n        /// destination image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver]. Regions that are entirely transparent in the source image take\n        /// their saturation from the destination.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_hue.png)\n        ///\n        /// See also:\n        ///\n        ///  * [color], which also applies the hue of the source image.\n        ///  * [luminosity], which applies the luminosity of the source image to the\n        ///    destination.\n        saturation,\n\n        /// Take the hue and saturation of the source image, and the luminosity of the\n        /// destination image.\n        ///\n        /// The effect is to tint the destination image with the source image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver]. Regions that are entirely transparent in the source image take\n        /// their hue and saturation from the destination.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_color.png)\n        ///\n        /// See also:\n        ///\n        ///  * [hue], which is a similar but weaker effect.\n        ///  * [softLight], which is a similar tinting effect but also tints white.\n        ///  * [saturation], which only applies the saturation of the source image.\n        color,\n\n        /// Take the luminosity of the source image, and the hue and saturation of the\n        /// destination image.\n        ///\n        /// The opacity of the output image is computed in the same way as for\n        /// [srcOver]. Regions that are entirely transparent in the source image take\n        /// their luminosity from the destination.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/blend_mode_luminosity.png)\n        ///\n        /// See also:\n        ///\n        ///  * [saturation], which applies the saturation of the source image to the\n        ///    destination.\n        ///  * [ImageFilter.blur], which can be used with [BackdropFilter] for a\n        ///    related effect.\n        luminosity,\n    }\n\n    /// Quality levels for image filters.\n    ///\n    /// See [Paint.filterQuality].\n    public enum FilterQuality\n    {\n        // This list comes from Skia's SkFilterQuality.h and the values (order) should\n        // be kept in sync.\n\n        /// Fastest possible filtering, albeit also the lowest quality.\n        ///\n        /// Typically this implies nearest-neighbour filtering.\n        none,\n\n        /// Better quality than [none], faster than [medium].\n        ///\n        /// Typically this implies bilinear interpolation.\n        low,\n\n        /// Better quality than [low], faster than [high].\n        ///\n        /// Typically this implies a combination of bilinear interpolation and\n        /// pyramidal parametric prefiltering (mipmaps).\n        medium,\n\n        /// Best possible quality filtering, albeit also the slowest.\n        ///\n        /// Typically this implies bicubic interpolation or better.\n        high,\n    }\n\n    /// Styles to use for line endings.\n    ///\n    /// See also:\n    ///\n    ///  * [Paint.strokeCap] for how this value is used.\n    ///  * [StrokeJoin] for the different kinds of line segment joins.\n    // These enum values must be kept in sync with SKPaint::Cap.\n    public enum StrokeCap\n    {\n        /// Begin and end contours with a flat edge and no extension.\n        ///\n        /// ![A butt cap ends line segments with a square end that stops at the end of\n        /// the line segment.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/butt_cap.png)\n        ///\n        /// Compare to the [square] cap, which has the same shape, but : past\n        /// the end of the line by half a stroke width.\n        butt,\n\n        /// Begin and end contours with a semi-circle extension.\n        ///\n        /// ![A round cap adds a rounded end to the line segment that protrudes\n        /// by one half of the thickness of the line (which is the radius of the cap)\n        /// past the end of the segment.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_cap.png)\n        ///\n        /// The cap is colored in the diagram above to highlight it: in normal use it\n        /// is the same color as the line.\n        round,\n\n        /// Begin and end contours with a half square extension. This is\n        /// similar to extending each contour by half the stroke width (as\n        /// given by [Paint.strokeWidth]).\n        ///\n        /// ![A square cap has a square end that effectively : the line length\n        /// by half of the stroke width.](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/square_cap.png)\n        ///\n        /// The cap is colored in the diagram above to highlight it: in normal use it\n        /// is the same color as the line.\n        ///\n        /// Compare to the [butt] cap, which has the same shape, but doesn't extend\n        /// past the end of the line.\n        square,\n    }\n\n    /// Styles to use for line segment joins.\n    ///\n    /// This only affects line joins for polygons drawn by [Canvas.drawPath] and\n    /// rectangles, not points drawn as lines with [Canvas.drawPoints].\n    ///\n    /// See also:\n    ///\n    /// * [Paint.strokeJoin] and [Paint.strokeMiterLimit] for how this value is\n    ///   used.\n    /// * [StrokeCap] for the different kinds of line endings.\n    // These enum values must be kept in sync with SKPaint::Join.\n    public enum StrokeJoin\n    {\n        /// Joins between line segments form sharp corners.\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}\n        ///\n        /// The center of the line segment is colored in the diagram above to\n        /// highlight the join, but in normal usage the join is the same color as the\n        /// line.\n        ///\n        /// See also:\n        ///\n        ///   * [Paint.strokeJoin], used to set the line segment join style to this\n        ///     value.\n        ///   * [Paint.strokeMiterLimit], used to define when a miter is drawn instead\n        ///     of a bevel when the join is set to this value.\n        miter,\n\n        /// Joins between line segments are semi-circular.\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4}\n        ///\n        /// The center of the line segment is colored in the diagram above to\n        /// highlight the join, but in normal usage the join is the same color as the\n        /// line.\n        ///\n        /// See also:\n        ///\n        ///   * [Paint.strokeJoin], used to set the line segment join style to this\n        ///     value.\n        round,\n\n        /// Joins between line segments connect the corners of the butt ends of the\n        /// line segments to give a beveled appearance.\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4}\n        ///\n        /// The center of the line segment is colored in the diagram above to\n        /// highlight the join, but in normal usage the join is the same color as the\n        /// line.\n        ///\n        /// See also:\n        ///\n        ///   * [Paint.strokeJoin], used to set the line segment join style to this\n        ///     value.\n        bevel,\n    }\n\n    /// Strategies for painting shapes and paths on a canvas.\n    ///\n    /// See [Paint.style].\n    // These enum values must be kept in sync with SKPaint::Style.\n    public enum PaintingStyle\n    {\n        // This list comes from Skia's SKPaint.h and the values (order) should be kept\n        // in sync.\n\n        /// Apply the [Paint] to the inside of the shape. For example, when\n        /// applied to the [Canvas.drawCircle] call, this results in a disc\n        /// of the given size being painted.\n        fill,\n\n        /// Apply the [Paint] to the edge of the shape. For example, when\n        /// applied to the [Canvas.drawCircle] call, this results is a hoop\n        /// of the given size being painted. The line drawn on the edge will\n        /// be the width given by the [Paint.strokeWidth] property.\n        stroke,\n    }\n\n\n    /// Different ways to clip a widget's content.\n    public enum Clip\n    {\n        /// No clip at all.\n        ///\n        /// This is the default option for most widgets: if the content does not\n        /// overflow the widget boundary, don't pay any performance cost for clipping.\n        ///\n        /// If the content does overflow, please explicitly specify the following\n        /// [Clip] options:\n        ///  * [hardEdge], which is the fastest clipping, but with lower fidelity.\n        ///  * [antiAlias], which is a little slower than [hardEdge], but with smoothed edges.\n        ///  * [antiAliasWithSaveLayer], which is much slower than [antiAlias], and should\n        ///    rarely be used.\n        none,\n\n        /// Clip, but do not apply anti-aliasing.\n        ///\n        /// This mode enables clipping, but curves and non-axis-aligned straight lines will be\n        /// jagged as no effort is made to anti-alias.\n        ///\n        /// Faster than other clipping modes, but slower than [none].\n        ///\n        /// This is a reasonable choice when clipping is needed, if the container is an axis-\n        /// aligned rectangle or an axis-aligned rounded rectangle with very small corner radii.\n        ///\n        /// See also:\n        ///\n        ///  * [antiAlias], which is more reasonable when clipping is needed and the shape is not\n        ///    an axis-aligned rectangle.\n        hardEdge,\n\n        /// Clip with anti-aliasing.\n        ///\n        /// This mode has anti-aliased clipping edges to achieve a smoother look.\n        ///\n        /// It' s much faster than [antiAliasWithSaveLayer], but slower than [hardEdge].\n        ///\n        /// This will be the common case when dealing with circles and arcs.\n        ///\n        /// Different from [hardEdge] and [antiAliasWithSaveLayer], this clipping may have\n        /// bleeding edge artifacts.\n        /// (See https://fiddle.skia.org/c/21cb4c2b2515996b537f36e7819288ae for an example.)\n        ///\n        /// See also:\n        ///\n        ///  * [hardEdge], which is a little faster, but with lower fidelity.\n        ///  * [antiAliasWithSaveLayer], which is much slower, but can avoid the\n        ///    bleeding edges if there's no other way.\n        ///  * [Paint.isAntiAlias], which is the anti-aliasing switch for general draw operations.\n        antiAlias,\n\n        /// Clip with anti-aliasing and saveLayer immediately following the clip.\n        ///\n        /// This mode not only clips with anti-aliasing, but also allocates an offscreen\n        /// buffer. All subsequent paints are carried out on that buffer before finally\n        /// being clipped and composited back.\n        ///\n        /// This is very slow. It has no bleeding edge artifacts (that [antiAlias] has)\n        /// but it changes the semantics as an offscreen buffer is now introduced.\n        /// (See https://github.com/flutter/flutter/issues/18057#issuecomment-394197336\n        /// for a difference between paint without saveLayer and paint with saveLayer.)\n        ///\n        /// This will be only rarely needed. One case where you might need this is if\n        /// you have an image overlaid on a very different background color. In these\n        /// cases, consider whether you can avoid overlaying multiple colors in one\n        /// spot (e.g. by having the background color only present where the image is\n        /// absent). If you can, [antiAlias] would be fine and much faster.\n        ///\n        /// See also:\n        ///\n        ///  * [antiAlias], which is much faster, and has similar clipping results.\n        antiAliasWithSaveLayer,\n    }\n\n\n    /// A description of the style to use when drawing on a [Canvas].\n    ///\n    /// Most APIs on [Canvas] take a [Paint] object to describe the style\n    /// to use for that operation.\n    public class Paint\n    {\n\n\n        // Paint objects are encoded in two buffers:\n        //\n        // * _data is binary data in four-byte fields, each of which is either a\n        //   uint or a float. The default value for each field is encoded as\n        //   zero to make initialization trivial. Most values already have a default\n        //   value of zero, but some, such as color, have a non-zero default value.\n        //   To encode or decode these values, XOR the value with the default value.\n        //\n        // * _objects is a list of unencodable objects, typically wrappers for native\n        //   objects. The objects are simply stored in the list without any additional\n        //   encoding.\n        //\n        // The binary format must match the deserialization code in paint.cc.\n\n        internal readonly ByteData _data = new ByteData(_kDataByteCount);\n        const int _kIsAntiAliasIndex = 0;\n        const int _kColorIndex = 1;\n        const int _kBlendModeIndex = 2;\n        const int _kStyleIndex = 3;\n        const int _kStrokeWidthIndex = 4;\n        const int _kStrokeCapIndex = 5;\n        const int _kStrokeJoinIndex = 6;\n        const int _kStrokeMiterLimitIndex = 7;\n        const int _kFilterQualityIndex = 8;\n        const int _kColorFilterIndex = 9;\n        const int _kColorFilterColorIndex = 10;\n        const int _kColorFilterBlendModeIndex = 11;\n        const int _kMaskFilterIndex = 12;\n        const int _kMaskFilterBlurStyleIndex = 13;\n        const int _kMaskFilterSigmaIndex = 14;\n        const int _kInvertColorIndex = 15;\n\n        const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2;\n        const int _kColorOffset = _kColorIndex << 2;\n        const int _kBlendModeOffset = _kBlendModeIndex << 2;\n        const int _kStyleOffset = _kStyleIndex << 2;\n        const int _kStrokeWidthOffset = _kStrokeWidthIndex << 2;\n        const int _kStrokeCapOffset = _kStrokeCapIndex << 2;\n        const int _kStrokeJoinOffset = _kStrokeJoinIndex << 2;\n        const int _kStrokeMiterLimitOffset = _kStrokeMiterLimitIndex << 2;\n        const int _kFilterQualityOffset = _kFilterQualityIndex << 2;\n        const int _kColorFilterOffset = _kColorFilterIndex << 2;\n        const int _kColorFilterColorOffset = _kColorFilterColorIndex << 2;\n        const int _kColorFilterBlendModeOffset = _kColorFilterBlendModeIndex << 2;\n        const int _kMaskFilterOffset = _kMaskFilterIndex << 2;\n        const int _kMaskFilterBlurStyleOffset = _kMaskFilterBlurStyleIndex << 2;\n        const int _kMaskFilterSigmaOffset = _kMaskFilterSigmaIndex << 2;\n        const int _kInvertColorOffset = _kInvertColorIndex << 2;\n        // If you add more fields, remember to update _kDataByteCount.\n        const int _kDataByteCount = 75;\n\n        // Binary format must match the deserialization code in paint.cc.\n        internal List<Object> _objects;\n        const int _kShaderIndex = 0;\n        const int _kObjectCount = 1; // Must be one larger than the largest index.\n\n        /// Whether to apply anti-aliasing to lines and images drawn on the\n        /// canvas.\n        ///\n        /// Defaults to true.\n        public bool isAntiAlias\n        {\n            get\n            {\n                return _data.getInt32(_kIsAntiAliasOffset, (int)_kFakeHostEndian) == 0;\n            }\n            set\n            {\n                // We encode true as zero and false as one because the default value, which\n                // we always encode as zero, is true.\n                int encoded = value ? 0 : 1;\n                _data.setInt32(_kIsAntiAliasOffset, encoded, (int)_kFakeHostEndian);\n            }\n\n        }\n\n        // Must be kept in sync with the default in paint.cc.\n        const uint _kColorDefault = 0xFF000000;\n\n        /// The color to use when stroking or filling a shape.\n        ///\n        /// Defaults to opaque black.\n        ///\n        /// See also:\n        ///\n        ///  * [style], which controls whether to stroke or fill (or both).\n        ///  * [colorFilter], which overrides [color].\n        ///  * [shader], which overrides [color] with more elaborate effects.\n        ///\n        /// This color is not used when compositing. To colorize a layer, use\n        /// [colorFilter].\n        public Color color\n        {\n            get\n            {\n                uint encoded = (uint)_data.getInt32(_kColorOffset, (int)_kFakeHostEndian);\n                return new Color(encoded ^ _kColorDefault);\n            }\n            set\n            {\n                //assert(value != null);\n                int encoded = (int)(value.value ^ _kColorDefault);\n                _data.setInt32(_kColorOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n\n        // Must be kept in sync with the default in paint.cc.\n        static readonly int _kBlendModeDefault = (int)BlendMode.srcOver;\n\n        /// A blend mode to apply when a shape is drawn or a layer is composited.\n        ///\n        /// The source colors are from the shape being drawn (e.g. from\n        /// [Canvas.drawPath]) or layer being composited (the graphics that were drawn\n        /// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying\n        /// the [colorFilter], if any.\n        ///\n        /// The destination colors are from the background onto which the shape or\n        /// layer is being composited.\n        ///\n        /// Defaults to [BlendMode.srcOver].\n        ///\n        /// See also:\n        ///\n        ///  * [Canvas.saveLayer], which uses its [Paint]'s [blendMode] to composite\n        ///    the layer when [restore] is called.\n        ///  * [BlendMode], which discusses the user of [saveLayer] with [blendMode].\n        public BlendMode blendMode\n        {\n            get\n            {\n                int encoded = _data.getInt32(_kBlendModeOffset, (int)_kFakeHostEndian);\n                return (BlendMode)(encoded ^ _kBlendModeDefault);\n            }\n            set\n            {\n                //assert(value != null);\n                int encoded = (int)value ^ _kBlendModeDefault;\n                _data.setInt32(_kBlendModeOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// Whether to paint inside shapes, the edges of shapes, or both.\n        ///\n        /// Defaults to [PaintingStyle.fill].\n        public PaintingStyle style\n        {\n            get\n            {\n                return (PaintingStyle)_data.getInt32(_kStyleOffset, (int)_kFakeHostEndian);\n            }\n            set\n            {\n                //assert(value != null);\n                int encoded = (int)value;\n                _data.setInt32(_kStyleOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// How wide to make edges drawn when [style] is set to\n        /// [PaintingStyle.stroke]. The width is given in logical pixels measured in\n        /// the direction orthogonal to the direction of the path.\n        ///\n        /// Defaults to 0.0, which correspond to a hairline width.\n        public double strokeWidth\n        {\n            get\n            {\n                return _data.getFloat32(_kStrokeWidthOffset, (int)_kFakeHostEndian);\n            }\n            set\n            {\n                //assert(value != null);\n                double encoded = value;\n                _data.setFloat32(_kStrokeWidthOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// The kind of finish to place on the end of lines drawn when\n        /// [style] is set to [PaintingStyle.stroke].\n        ///\n        /// Defaults to [StrokeCap.butt], i.e. no caps.\n        public StrokeCap strokeCap\n        {\n            get\n            {\n                return (StrokeCap)_data.getInt32(_kStrokeCapOffset, (int)_kFakeHostEndian);\n            }\n            set\n            {\n                int encoded = (int)value;\n                _data.setInt32(_kStrokeCapOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// The kind of finish to place on the joins between segments.\n        ///\n        /// This applies to paths drawn when [style] is set to [PaintingStyle.stroke],\n        /// It does not apply to points drawn as lines with [Canvas.drawPoints].\n        ///\n        /// Defaults to [StrokeJoin.miter], i.e. sharp corners.\n        ///\n        /// Some examples of joins:\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4}\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4}\n        ///\n        /// The centers of the line segments are colored in the diagrams above to\n        /// highlight the joins, but in normal usage the join is the same color as the\n        /// line.\n        ///\n        /// See also:\n        ///\n        ///  * [strokeMiterLimit] to control when miters are replaced by bevels when\n        ///    this is set to [StrokeJoin.miter].\n        ///  * [strokeCap] to control what is drawn at the ends of the stroke.\n        ///  * [StrokeJoin] for the definitive list of stroke joins.\n        public StrokeJoin strokeJoin\n        {\n            get\n            {\n                return (StrokeJoin)_data.getInt32(_kStrokeJoinOffset, (int)_kFakeHostEndian);\n            }\n            set\n            {\n                //assert(value != null);\n                int encoded = (int)value;\n                _data.setInt32(_kStrokeJoinOffset, encoded, (int)_kFakeHostEndian);\n\n            }\n        }\n\n        // Must be kept in sync with the default in paint.cc.\n        const double _kStrokeMiterLimitDefault = 4.0;\n\n        /// The limit for miters to be drawn on segments when the join is set to\n        /// [StrokeJoin.miter] and the [style] is set to [PaintingStyle.stroke]. If\n        /// this limit is exceeded, then a [StrokeJoin.bevel] join will be drawn\n        /// instead. This may cause some 'popping' of the corners of a path if the\n        /// angle between line segments is animated, as seen in the diagrams below.\n        ///\n        /// This limit is expressed as a limit on the length of the miter.\n        ///\n        /// Defaults to 4.0.  Using zero as a limit will cause a [StrokeJoin.bevel]\n        /// join to be used all the time.\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_0_join.mp4}\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}\n        ///\n        /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_6_join.mp4}\n        ///\n        /// The centers of the line segments are colored in the diagrams above to\n        /// highlight the joins, but in normal usage the join is the same color as the\n        /// line.\n        ///\n        /// See also:\n        ///\n        ///  * [strokeJoin] to control the kind of finish to place on the joins\n        ///    between segments.\n        ///  * [strokeCap] to control what is drawn at the ends of the stroke.\n        public double strokeMiterLimit\n        {\n            get\n            {\n                return _data.getFloat32(_kStrokeMiterLimitOffset, (int)_kFakeHostEndian);\n            }\n            set\n            {\n                //assert(value != null);\n                double encoded = value - _kStrokeMiterLimitDefault;\n                _data.setFloat32(_kStrokeMiterLimitOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// A mask filter (for example, a blur) to apply to a shape after it has been\n        /// drawn but before it has been composited into the image.\n        ///\n        /// See [MaskFilter] for details.\n        public MaskFilter maskFilter\n        {\n            get\n            {\n                switch (_data.getInt32(_kMaskFilterOffset, (int)_kFakeHostEndian))\n                {\n                    case MaskFilter._TypeNone:\n                        return null;\n                    case MaskFilter._TypeBlur:\n                        return MaskFilter.blur(\n                          (BlurStyle)_data.getInt32(_kMaskFilterBlurStyleOffset, (int)_kFakeHostEndian),\n                          _data.getFloat32(_kMaskFilterSigmaOffset, (int)_kFakeHostEndian));\n                }\n                return null;\n            }\n            set\n            {\n                if (value == null)\n                {\n                    _data.setInt32(_kMaskFilterOffset, MaskFilter._TypeNone, (int)_kFakeHostEndian);\n                    _data.setInt32(_kMaskFilterBlurStyleOffset, 0, (int)_kFakeHostEndian);\n                    _data.setFloat32(_kMaskFilterSigmaOffset, 0.0, (int)_kFakeHostEndian);\n                }\n                else\n                {\n                    // For now we only support one kind of MaskFilter, so we don't need to\n                    // check what the type is if it's not null.\n                    _data.setInt32(_kMaskFilterOffset, MaskFilter._TypeBlur, (int)_kFakeHostEndian);\n                    _data.setInt32(_kMaskFilterBlurStyleOffset, (int)value._style, (int)_kFakeHostEndian);\n                    _data.setFloat32(_kMaskFilterSigmaOffset, value._sigma, (int)_kFakeHostEndian);\n                }\n            }\n        }\n\n        /// Controls the performance vs quality trade-off to use when applying\n        /// filters, such as [maskFilter], or when drawing images, as with\n        /// [Canvas.drawImageRect] or [Canvas.drawImageNine].\n        ///\n        /// Defaults to [FilterQuality.none].\n        // TODO(ianh): verify that the image drawing methods actually respect this\n        public FilterQuality filterQuality\n        {\n            get\n            {\n                return (FilterQuality)(_data.getInt32(_kFilterQualityOffset, (int)_kFakeHostEndian));\n            }\n            set\n            {\n                //assert(value != null);\n                int encoded = (int)value;\n                _data.setInt32(_kFilterQualityOffset, encoded, (int)_kFakeHostEndian);\n            }\n        }\n\n        /// The shader to use when stroking or filling a shape.\n        ///\n        /// When this is null, the [color] is used instead.\n        ///\n        /// See also:\n        ///\n        ///  * [Gradient], a shader that paints a color gradient.\n        ///  * [ImageShader], a shader that tiles an [Image].\n        ///  * [colorFilter], which overrides [shader].\n        ///  * [color], which is used if [shader] and [colorFilter] are null.\n        public SKShader shader\n        {\n            get\n            {\n                if (_objects == null)\n                    return null;\n                return (SKShader)_objects[_kShaderIndex];\n            }\n            set\n            {\n                if (_objects == null)\n                    _objects = new List<Object>(_kObjectCount);\n                _objects[_kShaderIndex] = value;\n            }\n        }\n\n        /// A color filter to apply when a shape is drawn or when a layer is\n        /// composited.\n        ///\n        /// See [ColorFilter] for details.\n        ///\n        /// When a shape is being drawn, [colorFilter] overrides [color] and [shader].\n        public ColorFilter colorFilter\n        {\n            get\n            {\n                bool isNull = _data.getInt32(_kColorFilterOffset, (int)_kFakeHostEndian) == 0;\n                if (isNull)\n                    return null;\n                return ColorFilter.mode(\n                  new Color((uint)_data.getInt32(_kColorFilterColorOffset, (int)_kFakeHostEndian)),\n                  (BlendMode)(_data.getInt32(_kColorFilterBlendModeOffset, (int)_kFakeHostEndian))\n                );\n            }\n            set\n            {\n                if (value == null)\n                {\n                    _data.setInt32(_kColorFilterOffset, 0, (int)_kFakeHostEndian);\n                    _data.setInt32(_kColorFilterColorOffset, 0, (int)_kFakeHostEndian);\n                    _data.setInt32(_kColorFilterBlendModeOffset, 0, (int)_kFakeHostEndian);\n                }\n                else\n                {\n                    _data.setInt32(_kColorFilterOffset, 1, (int)_kFakeHostEndian);\n                    _data.setInt32(_kColorFilterColorOffset, (int)value._color.value, (int)_kFakeHostEndian);\n                    _data.setInt32(_kColorFilterBlendModeOffset, (int)value._blendMode, (int)_kFakeHostEndian);\n                }\n            }\n        }\n\n        /// Whether the colors of the image are inverted when drawn.\n        ///\n        /// inverting the colors of an image applies a new color filter that will\n        /// be composed with any user provided color filters. This is primarily\n        /// used for implementing smart invert on iOS.\n        public bool invertColors\n        {\n            get\n            {\n                return _data.getInt32(_kInvertColorOffset, (int)_kFakeHostEndian) == 1;\n            }\n            set\n            {\n                _data.setInt32(_kInvertColorOffset, value ? 1 : 0, (int)_kFakeHostEndian);\n            }\n        }\n\n        public String toString()\n        {\n            StringBuilder result = new StringBuilder();\n            String semicolon = \"\";\n            result.Append(\"Paint(\");\n            if (style == PaintingStyle.stroke)\n            {\n                result.Append($\"{style}\");\n                if (strokeWidth != 0.0)\n                    result.Append($\" {strokeWidth.toStringAsFixed(1)}\");\n                else\n                    result.Append(\" hairline\");\n                if (strokeCap != StrokeCap.butt)\n                    result.Append($\" {strokeCap}\");\n                if (strokeJoin == StrokeJoin.miter)\n                {\n                    if (strokeMiterLimit != _kStrokeMiterLimitDefault)\n                        result.Append($\" {strokeJoin} up to ${strokeMiterLimit.toStringAsFixed(1)}\");\n                }\n                else\n                {\n                    result.Append($\" {strokeJoin}\");\n                }\n                semicolon = \"; \";\n            }\n            if (isAntiAlias != true)\n            {\n                result.Append($\"{semicolon}antialias off\");\n                semicolon = \"; \";\n            }\n            if (color != new Color(_kColorDefault))\n            {\n                if (color != null)\n                    result.Append($\"{semicolon}{color}\");\n                else\n                    result.Append($\"{semicolon}no color\");\n                semicolon = \"; \";\n            }\n            if ((int)blendMode != _kBlendModeDefault)\n            {\n                result.Append($\"{semicolon}{blendMode}\");\n                semicolon = \"; \";\n            }\n            if (colorFilter != null)\n            {\n                result.Append($\"{semicolon}colorFilter: {colorFilter}\");\n                semicolon = \"; \";\n            }\n            if (maskFilter != null)\n            {\n                result.Append($\"{semicolon}maskFilter: {maskFilter}\");\n                semicolon = \"; \";\n            }\n            if (filterQuality != FilterQuality.none)\n            {\n                result.Append($\"{semicolon}filterQuality: {filterQuality}\");\n                semicolon = \"; \";\n            }\n            if (shader != null)\n            {\n                result.Append($\"{semicolon}shader: {shader}\");\n                semicolon = \"; \";\n            }\n            if (invertColors)\n                result.Append($\"{semicolon}invert: {invertColors}\");\n            result.Append(\")\");\n            return result.ToString();\n        }\n    }\n\n    /// The format in which image bytes should be returned when using\n    /// [Image.toByteData].\n    public enum ImageByteFormat\n    {\n        /// Raw RGBA format.\n        ///\n        /// Unencoded bytes, in RGBA row-primary form, 8 bits per channel.\n        rawRgba,\n\n        /// Raw unmodified format.\n        ///\n        /// Unencoded bytes, in the image's existing format. For example, a grayscale\n        /// image may use a single 8-bit channel for each pixel.\n        rawUnmodified,\n\n        /// PNG format.\n        ///\n        /// A loss-less compression format for images. This format is well suited for\n        /// images with hard edges, such as screenshots or sprites, and images with\n        /// text. Transparency is supported. The PNG format supports images up to\n        /// 2,147,483,647 pixels in either dimension, though in practice available\n        /// memory provides a more immediate limitation on maximum image size.\n        ///\n        /// PNG images normally use the `.png` file extension and the `image/png` MIME\n        /// type.\n        ///\n        /// See also:\n        ///\n        ///  * <https://en.wikipedia.org/wiki/Portable_Network_Graphics>, the Wikipedia page on PNG.\n        ///  * <https://tools.ietf.org/rfc/rfc2083.txt>, the PNG standard.\n        png,\n    }\n\n    /// The format of pixel data given to [decodeImageFromPixels].\n    public enum PixelFormat\n    {\n        /// Each pixel is 32 bits, with the highest 8 bits encoding red, the next 8\n        /// bits encoding green, the next 8 bits encoding blue, and the lowest 8 bits\n        /// encoding alpha.\n        rgba8888,\n\n        /// Each pixel is 32 bits, with the highest 8 bits encoding blue, the next 8\n        /// bits encoding green, the next 8 bits encoding red, and the lowest 8 bits\n        /// encoding alpha.\n        bgra8888,\n    }\n\n    public class _ImageInfo\n    {\n        public _ImageInfo(int width, int height, int format, int? rowBytes)\n        {\n            this.width = width;\n            this.height = height;\n            this.format = format;\n\n            if (rowBytes == null)\n                this.rowBytes = width * 4;\n            else\n                this.rowBytes = rowBytes.Value;\n        }\n\n        int width;\n        int height;\n        int format;\n        int rowBytes;\n    }\n\n    /// Callback signature for [decodeImageFromList].\n    public delegate void ImageDecoderCallback(SKImage result);\n\n    /// Determines the winding rule that decides how the interior of a [Path] is\n    /// calculated.\n    ///\n    /// This enum is used by the [Path.fillType] property.\n    public enum PathFillType\n    {\n        /// The interior is defined by a non-zero sum of signed edge crossings.\n        ///\n        /// For a given point, the point is considered to be on the inside of the path\n        /// if a line drawn from the point to infinity crosses lines going clockwise\n        /// around the point a different number of times than it crosses lines going\n        /// counter-clockwise around that point.\n        ///\n        /// See: <https://en.wikipedia.org/wiki/Nonzero-rule>\n        nonZero,\n\n        /// The interior is defined by an odd number of edge crossings.\n        ///\n        /// For a given point, the point is considered to be on the inside of the path\n        /// if a line drawn from the point to infinity crosses an odd number of lines.\n        ///\n        /// See: <https://en.wikipedia.org/wiki/Even-odd_rule>\n        evenOdd,\n    }\n\n    /// Strategies for combining paths.\n    ///\n    /// See also:\n    ///\n    /// * [Path.combine], which uses this enum to decide how to combine two paths.\n    // Must be kept in sync with SKPathOp\n    public enum PathOperation\n    {\n        /// Subtract the second path from the first path.\n        ///\n        /// For example, if the two paths are overlapping circles of equal diameter\n        /// but differing centers, the result would be a crescent portion of the\n        /// first circle that was not overlapped by the second circle.\n        ///\n        /// See also:\n        ///\n        ///  * [reverseDifference], which is the same but subtracting the first path\n        ///    from the second.\n        difference,\n        /// Create a new path that is the intersection of the two paths, leaving the\n        /// overlapping pieces of the path.\n        ///\n        /// For example, if the two paths are overlapping circles of equal diameter\n        /// but differing centers, the result would be only the overlapping portion\n        /// of the two circles.\n        ///\n        /// See also:\n        ///  * [xor], which is the inverse of this operation\n        intersect,\n        /// Create a new path that is the union (inclusive-or) of the two paths.\n        ///\n        /// For example, if the two paths are overlapping circles of equal diameter\n        /// but differing centers, the result would be a figure-eight like shape\n        /// matching the outer boundaries of both circles.\n        union,\n        /// Create a new path that is the exclusive-or of the two paths, leaving\n        /// everything but the overlapping pieces of the path.\n        ///\n        /// For example, if the two paths are overlapping circles of equal diameter\n        /// but differing centers, the figure-eight like shape less the overlapping parts\n        ///\n        /// See also:\n        ///  * [intersect], which is the inverse of this operation\n        xor,\n        /// Subtract the first path from the second path.\n        ///\n        /// For example, if the two paths are overlapping circles of equal diameter\n        /// but differing centers, the result would be a crescent portion of the\n        /// second circle that was not overlapped by the first circle.\n        ///\n        /// See also:\n        ///\n        ///  * [difference], which is the same but subtracting the second path\n        ///    from the first.\n        reverseDifference,\n    }\n\n    /// A complex, one-dimensional subset of a plane.\n    ///\n    /// A path consists of a number of subpaths, and a _current point_.\n    ///\n    /// Subpaths consist of segments of various types, such as lines,\n    /// arcs, or beziers. Subpaths can be open or closed, and can\n    /// self-intersect.\n    ///\n    /// Closed subpaths enclose a (possibly discontiguous) region of the\n    /// plane based on the current [fillType].\n    ///\n    /// The _current point_ is initially at the origin. After each\n    /// operation adding a segment to a subpath, the current point is\n    /// updated to the end of that segment.\n    ///\n    /// Paths can be drawn on canvases using [Canvas.drawPath], and can\n    /// used to create clip regions using [Canvas.clipPath].\n    public class Path : NativePath\n    {\n        /// Create a new empty [Path] object.\n        public Path() { _constructor(); }\n        void _constructor()\n        {\n            // [DONE] native 'Path_constructor';\n        }\n\n        /// Creates a copy of another [Path].\n        ///\n        /// This copy is fast and does not require additional memory unless either\n        /// the `source` path or the path returned by this constructor are modified.\n        public static Path from(Path source)\n        {\n            return source._clone();\n        }\n        Path _clone()\n        {\n            return (Path)this.MemberwiseClone();\n        }\n\n        /// Determines how the interior of this path is calculated.\n        ///\n        /// Defaults to the non-zero winding rule, [PathFillType.nonZero].\n        public PathFillType fillType\n        {\n            get => (PathFillType)_getFillType();\n            set => _setFillType((int)value);\n        }\n\n        int _getFillType()\n        {\n            return (int)this.FillType;\n        }\n        void _setFillType(int fillType)\n        {\n            this.FillType = (SKPathFillType)fillType;\n        }\n\n        /// Starts a new subpath at the given coordinate.\n        public void moveTo(double x, double y)\n        {\n            this.MoveTo((float)x, (float)y);\n        }\n\n        /// Starts a new subpath at the given offset from the current point.\n        public void relativeMoveTo(double dx, double dy)\n        {\n            this.RMoveTo((float)dx, (float)dy);\n        }\n\n        /// Adds a straight line segment from the current point to the given\n        /// point.\n        public void lineTo(double x, double y)\n        {\n            this.LineTo((float)x, (float)y);\n        }\n\n        /// Adds a straight line segment from the current point to the point\n        /// at the given offset from the current point.\n        public void relativeLineTo(double dx, double dy)\n        {\n            this.RLineTo((float)dx, (float)dy);\n        }\n\n        /// Adds a quadratic bezier segment that curves from the current\n        /// point to the given point (x2,y2), using the control point\n        /// (x1,y1).\n        public void quadraticBezierTo(double x1, double y1, double x2, double y2)\n        {\n            this.QuadTo((float)x1, (float)y1, (float)x2, (float)y2);\n        }\n\n        /// Adds a quadratic bezier segment that curves from the current\n        /// point to the point at the offset (x2,y2) from the current point,\n        /// using the control point at the offset (x1,y1) from the current\n        /// point.\n        public void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2)\n        {\n            this.RQuadTo((float)x1, (float)y1, (float)x2, (float)y2);\n        }\n\n        /// Adds a cubic bezier segment that curves from the current point\n        /// to the given point (x3,y3), using the control points (x1,y1) and\n        /// (x2,y2).\n        public void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)\n        {\n            this.CubicTo((float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3);\n        }\n\n        /// Adds a cubic bezier segment that curves from the current point\n        /// to the point at the offset (x3,y3) from the current point, using\n        /// the control points at the offsets (x1,y1) and (x2,y2) from the\n        /// current point.\n        public void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3)\n        {\n            this.RCubicTo((float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3);\n        }\n\n        /// Adds a bezier segment that curves from the current point to the\n        /// given point (x2,y2), using the control points (x1,y1) and the\n        /// weight w. If the weight is greater than 1, then the curve is a\n        /// hyperbola; if the weight equals 1, it's a parabola; and if it is\n        /// less than 1, it is an ellipse.\n        public void conicTo(double x1, double y1, double x2, double y2, double w)\n        {\n            this.ConicTo((float)x1, (float)y1, (float)x2, (float)y2, (float)w);\n        }\n\n        /// Adds a bezier segment that curves from the current point to the\n        /// point at the offset (x2,y2) from the current point, using the\n        /// control point at the offset (x1,y1) from the current point and\n        /// the weight w. If the weight is greater than 1, then the curve is\n        /// a hyperbola; if the weight equals 1, it's a parabola; and if it\n        /// is less than 1, it is an ellipse.\n        public void relativeConicTo(double x1, double y1, double x2, double y2, double w)\n        {\n            this.RConicTo((float)x1, (float)y1, (float)x2, (float)y2, (float)w);\n        }\n\n        /// If the `forceMoveTo` argument is false, adds a straight line\n        /// segment and an arc segment.\n        ///\n        /// If the `forceMoveTo` argument is true, starts a new subpath\n        /// consisting of an arc segment.\n        ///\n        /// In either case, the arc segment consists of the arc that follows\n        /// the edge of the oval bounded by the given rectangle, from\n        /// startAngle radians around the oval up to startAngle + sweepAngle\n        /// radians around the oval, with zero radians being the point on\n        /// the right hand side of the oval that crosses the horizontal line\n        /// that intersects the center of the rectangle and with positive\n        /// angles going clockwise around the oval.\n        ///\n        /// The line segment added if `forceMoveTo` is false starts at the\n        /// current point and ends at the start of the arc.\n        public void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)\n        {\n            _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);\n        }\n        void _arcTo(double left, double top, double right, double bottom,\n                    double startAngle, double sweepAngle, bool forceMoveTo)\n        {\n            this.ArcTo(new SKRect((float)left, (float)top, (float)right, (float)bottom), (float)startAngle, (float)sweepAngle, forceMoveTo);\n        }\n\n        /// Appends up to four conic curves weighted to describe an oval of `radius`\n        /// and rotated by `rotation`.\n        ///\n        /// The first curve begins from the last point in the path and the last ends\n        /// at `arcEnd`. The curves follow a path in a direction determined by\n        /// `clockwise` and `largeArc` in such a way that the sweep angle\n        /// is always less than 360 degrees.\n        ///\n        /// A simple line is appended if either either radii are zero or the last\n        /// point in the path is `arcEnd`. The radii are scaled to fit the last path\n        /// point if both are greater than zero but too small to describe an arc.\n        ///\n        public void arcToPoint(Offset arcEnd,\n            Radius radius = null,\n        double rotation = 0.0,\n        bool largeArc = false,\n        bool clockwise = true)\n        {\n            if (radius == null)\n                radius = Radius.zero;\n            //assert(_offsetIsValid(arcEnd));\n            //assert(_radiusIsValid(radius));\n            _arcToPoint(arcEnd.dx, arcEnd.dy, radius.x, radius.y, rotation,\n                        largeArc, clockwise);\n        }\n        void _arcToPoint(double arcEndX, double arcEndY, double radiusX,\n                         double radiusY, double rotation, bool largeArc,\n                         bool clockwise)\n        {\n            var arcSize = largeArc ? SKPathArcSize.Large : SKPathArcSize.Small;\n\n            var direction = clockwise ? SKPathDirection.Clockwise : SKPathDirection.CounterClockwise;\n\n            this.ArcTo((float)radiusX, (float)radiusY, (float)rotation, arcSize, direction, (float)arcEndX,\n                        (float)arcEndY);\n        }\n\n\n        /// Appends up to four conic curves weighted to describe an oval of `radius`\n        /// and rotated by `rotation`.\n        ///\n        /// The last path point is described by (px, py).\n        ///\n        /// The first curve begins from the last point in the path and the last ends\n        /// at `arcEndDelta.dx + px` and `arcEndDelta.dy + py`. The curves follow a\n        /// path in a direction determined by `clockwise` and `largeArc`\n        /// in such a way that the sweep angle is always less than 360 degrees.\n        ///\n        /// A simple line is appended if either either radii are zero, or, both\n        /// `arcEndDelta.dx` and `arcEndDelta.dy` are zero. The radii are scaled to\n        /// fit the last path point if both are greater than zero but too small to\n        /// describe an arc.\n        public void relativeArcToPoint(Offset arcEndDelta,\n              Radius radius = null,\n          double rotation = 0.0,\n          bool largeArc = false,\n          bool clockwise = true)\n        {\n            if (radius == null)\n                radius = Radius.zero;\n            //assert(_offsetIsValid(arcEndDelta));\n            //assert(_radiusIsValid(radius));\n            _relativeArcToPoint(arcEndDelta.dx, arcEndDelta.dy, radius.x, radius.y,\n                                rotation, largeArc, clockwise);\n        }\n        void _relativeArcToPoint(double arcEndX, double arcEndY, double radiusX,\n                                 double radiusY, double rotation,\n                                 bool largeArc, bool clockwise)\n        {\n\n            var arcSize = largeArc ? SKPathArcSize.Large : SKPathArcSize.Small;\n\n            var direction = clockwise ? SKPathDirection.Clockwise : SKPathDirection.CounterClockwise;\n\n            this.RArcTo((float)radiusX, (float)radiusY, (float)rotation, arcSize, direction, (float)arcEndX,\n                        (float)arcEndY);\n        }\n\n        /// Adds a new subpath that consists of four lines that outline the\n        /// given rectangle.\n        public void addRect(Rect rect)\n        {\n            //assert(_rectIsValid(rect));\n            _addRect(rect.left, rect.top, rect.right, rect.bottom);\n        }\n        void _addRect(double left, double top, double right, double bottom)\n        {\n            this.AddRect(new SKRect((float)left, (float)top, (float)right, (float)bottom));\n        }\n\n        /// Adds a new subpath that consists of a curve that forms the\n        /// ellipse that fills the given rectangle.\n        ///\n        /// To add a circle, pass an appropriate rectangle as `oval`. [Rect.fromCircle]\n        /// can be used to easily describe the circle's center [Offset] and radius.\n        public void addOval(Rect oval)\n        {\n            //assert(_rectIsValid(oval));\n            _addOval(oval.left, oval.top, oval.right, oval.bottom);\n        }\n        void _addOval(double left, double top, double right, double bottom)\n        {\n            this.AddOval(new SKRect((float)left, (float)top, (float)right, (float)bottom));\n        }\n\n        /// Adds a new subpath with one arc segment that consists of the arc\n        /// that follows the edge of the oval bounded by the given\n        /// rectangle, from startAngle radians around the oval up to\n        /// startAngle + sweepAngle radians around the oval, with zero\n        /// radians being the point on the right hand side of the oval that\n        /// crosses the horizontal line that intersects the center of the\n        /// rectangle and with positive angles going clockwise around the\n        /// oval.\n        public void addArc(Rect oval, double startAngle, double sweepAngle)\n        {\n            //assert(_rectIsValid(oval));\n            _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);\n        }\n        void _addArc(double left, double top, double right, double bottom,\n                     double startAngle, double sweepAngle)\n        {\n            this.AddArc(new SKRect((float)left, (float)top, (float)right, (float)bottom), (float)startAngle, (float)sweepAngle);\n        }\n\n        /// Adds a new subpath with a sequence of line segments that connect the given\n        /// points.\n        ///\n        /// If `close` is true, a final line segment will be added that connects the\n        /// last point to the first point.\n        ///\n        /// The `points` argument is interpreted as offsets from the origin.\n        public void addPolygon(List<Offset> points, bool close)\n        {\n            //assert(points != null);\n            _addPolygon(points, close);\n        }\n        void _addPolygon(List<Offset> points, bool close)\n        {\n            var list = new List<SKPoint>();\n            foreach (var point in points)\n                list.Add(new SKPoint((float)point.dx, (float)point.dy));\n            this.AddPoly(list.ToArray(), close);\n        }\n\n        /// Adds a new subpath that consists of the straight lines and\n        /// curves needed to form the rounded rectangle described by the\n        /// argument.\n        public void addRRect(RRect rrect)\n        {\n            //assert(_rrectIsValid(rrect));\n            //_addRRect(rrect._value);\n            this.AddRoundedRect(new SKRect((float)rrect.left, (float)rrect.top, (float)rrect.right, (float)rrect.bottom), (float)rrect.tlRadiusX, (float)rrect.tlRadiusY);\n        }\n\n\n        /// Adds a new subpath that consists of the given `path` offset by the given\n        /// `offset`.\n        ///\n        /// If `matrix4` is specified, the path will be transformed by this matrix\n        /// after the matrix is translated by the given offset. The matrix is a 4x4\n        /// matrix stored in column major order.\n        public void addPath(Path path, Offset offset, List<float> matrix4 = null)\n        {\n            //assert(path != null); // path is checked on the engine side\n            //assert(_offsetIsValid(offset));\n            if (matrix4 != null)\n            {\n                //assert(_matrix4IsValid(matrix4));\n                _addPathWithMatrix(path, offset.dx, offset.dy, matrix4);\n            }\n            else\n            {\n                _addPath(path, offset.dx, offset.dy);\n            }\n        }\n        void _addPath(Path path, double dx, double dy)\n        {\n            this.AddPath(path, (float)dx, (float)dy);\n        }\n        void _addPathWithMatrix(Path path, double dx, double dy, List<float> matrix)\n        {\n            var skMatrix = Matrix.ToSkMatrix(matrix);\n            skMatrix.TransX += (float)dx;\n            skMatrix.TransY += (float)dy;\n            this.AddPath(path, ref skMatrix);\n        }\n\n        /// Adds the given path to this path by extending the current segment of this\n        /// path with the the first segment of the given path.\n        ///\n        /// If `matrix4` is specified, the path will be transformed by this matrix\n        /// after the matrix is translated by the given `offset`.  The matrix is a 4x4\n        /// matrix stored in column major order.\n        public void extendWithPath(Path path, Offset offset, List<float> matrix4 = null)\n        {\n            //assert(path != null); // path is checked on the engine side\n            //assert(_offsetIsValid(offset));\n            if (matrix4 != null)\n            {\n                //assert(_matrix4IsValid(matrix4));\n                _extendWithPathAndMatrix(path, offset.dx, offset.dy, matrix4);\n            }\n            else\n            {\n                _extendWithPath(path, offset.dx, offset.dy);\n            }\n        }\n        void _extendWithPath(Path path, double dx, double dy)\n        {\n            this.AddPath(path, (float)dx, (float)dy, SKPathAddMode.Extend);\n        }\n\n        void _extendWithPathAndMatrix(Path path, double dx, double dy, List<float> matrix)\n        {\n            var skMatrix = Matrix.ToSkMatrix(matrix);\n            skMatrix.TransX += (float)dx;\n            skMatrix.TransY += (float)dy;\n            this.AddPath(path, ref skMatrix, SKPathAddMode.Extend);\n        }\n\n        /// Closes the last subpath, as if a straight line had been drawn\n        /// from the current point to the first point of the subpath.\n        public void close()\n        {\n            this.Close();\n        }\n\n        /// Clears the [Path] object of all subpaths, returning it to the\n        /// same state it had when it was created. The _current point_ is\n        /// reset to the origin.\n        public void reset()\n        {\n            this.Reset();\n        }\n\n        /// Tests to see if the given point is within the path. (That is, whether the\n        /// point would be in the visible portion of the path if the path was used\n        /// with [Canvas.clipPath].)\n        ///\n        /// The `point` argument is interpreted as an offset from the origin.\n        ///\n        /// Returns true if the point is in the path, and false otherwise.\n        public bool contains(Offset point)\n        {\n            //assert(_offsetIsValid(point));\n            return _contains(point.dx, point.dy);\n        }\n        bool _contains(double x, double y)\n        {\n            return this.Contains((float)x, (float)y);\n        }\n\n        /// Returns a copy of the path with all the segments of every\n        /// subpath translated by the given offset.\n        public Path shift(Offset offset)\n        {\n            //assert(_offsetIsValid(offset));\n            return _shift(offset.dx, offset.dy);\n        }\n        Path _shift(double dx, double dy)\n        {\n            var path = this._clone();\n            path.Offset((float)dx, (float)dy);\n            return path;\n        }\n\n        /// Returns a copy of the path with all the segments of every\n        /// subpath transformed by the given matrix.\n        public Path transform(List<float> matrix4)\n        {\n            //assert(_matrix4IsValid(matrix4));\n            return _transform(matrix4);\n        }\n        Path _transform(List<float> matrix4)\n        {\n            var path = this._clone();\n            this.Transform(Matrix.ToSkMatrix(matrix4));\n            return path;\n        }\n\n        /// Computes the bounding rectangle for this path.\n        ///\n        /// A path containing only axis-aligned points on the same straight line will\n        /// have no area, and therefore `Rect.isEmpty` will return true for such a\n        /// path. Consider checking `rect.width + rect.height > 0.0` instead, or\n        /// using the [computeMetrics] API to check the path length.\n        ///\n        /// For many more elaborate paths, the bounds may be inaccurate.  For example,\n        /// when a path contains a circle, the points used to compute the bounds are\n        /// the circle's implied control points, which form a square around the circle;\n        /// if the circle has a transformation applied using [transform] then that\n        /// square is rotated, and the (axis-aligned, non-rotated) bounding box\n        /// therefore ends up grossly overestimating the actual area covered by the\n        /// circle.\n        // see https://skia.org/user/api/SKPath_Reference#SKPath_getBounds\n        public Rect getBounds()\n        {\n            List<float> rect = _getBounds();\n            return Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]);\n        }\n        List<float> _getBounds()\n        {\n            var skRect = new SKRect();\n            this.GetBounds(out skRect);\n            return new List<float>()\n            {\n                skRect.Left,\n                skRect.Top,\n                skRect.Right,\n                skRect.Bottom\n            };\n        }\n\n        /// Combines the two paths according to the manner specified by the given\n        /// `operation`.\n        ///\n        /// The resulting path will be constructed from non-overlapping contours. The\n        /// curve order is reduced where possible so that cubics may be turned into\n        /// quadratics, and quadratics maybe turned into lines.\n        public static Path combine(PathOperation operation, Path path1, Path path2)\n        {\n            //assert(path1 != null);\n            //assert(path2 != null);\n            Path path = new Path();\n            if (path1.Op(path2, (SKPathOp)operation, path))\n            {\n                return path;\n            }\n            throw new StateError(\"Path.combine() failed.  This may be due an invalid path; in particular, check for NaN values.\");\n        }\n\n        /// Creates a [PathMetrics] object for this path.\n        ///\n        /// If `forceClosed` is set to true, the contours of the path will be measured\n        /// as if they had been closed, even if they were not explicitly closed.\n        public PathMetrics computeMetrics(bool forceClosed = false)\n        {\n            return new PathMetrics(this, forceClosed);\n        }\n    }\n\n    /// The geometric description of a tangent: the angle at a point.\n    ///\n    /// See also:\n    ///  * [PathMetric.getTangentForOffset], which returns the tangent of an offset along a path.\n    public class Tangent\n    {\n        /// Creates a [Tangent] with the given values.\n        ///\n        /// The arguments must not be null.\n        public Tangent(Offset position, Offset vector)\n        {\n            //assert(position != null),\n            //assert(vector != null);\n            this.position = position;\n            this.vector = vector;\n        }\n\n\n        /// Creates a [Tangent] based on the angle rather than the vector.\n        ///\n        /// The [vector] is computed to be the unit vector at the given angle, interpreted\n        /// as clockwise radians from the x axis.\n        public static Tangent fromAngle(Offset position, double angle)\n        {\n            return new Tangent(position, new Offset(Math.Cos(angle), Math.Sin(angle)));\n        }\n\n        /// Position of the tangent.\n        ///\n        /// When used with [PathMetric.getTangentForOffset], this represents the precise\n        /// position that the given offset along the path corresponds to.\n        public readonly Offset position;\n\n        /// The vector of the curve at [position].\n        ///\n        /// When used with [PathMetric.getTangentForOffset], this is the vector of the\n        /// curve that is at the given offset along the path (i.e. the direction of the\n        /// curve at [position]).\n        public readonly Offset vector;\n\n        /// The direction of the curve at [position].\n        ///\n        /// When used with [PathMetric.getTangentForOffset], this is the angle of the\n        /// curve that is the given offset along the path (i.e. the direction of the\n        /// curve at [position]).\n        ///\n        /// This value is in radians, with 0.0 meaning pointing along the x axis in\n        /// the positive x-axis direction, positive numbers pointing downward toward\n        /// the negative y-axis, i.e. in a clockwise direction, and negative numbers\n        /// pointing upward toward the positive y-axis, i.e. in a counter-clockwise\n        /// direction.\n        // flip the sign to be consistent with [Path.arcTo]'s `sweepAngle`\n        public double angle => -Math.Atan2(vector.dy, vector.dx);\n    }\n\n    /// An iterable collection of [PathMetric] objects describing a [Path].\n    ///\n    /// A [PathMetrics] object is created by using the [Path.computeMetrics] method,\n    /// and represents the path as it stood at the time of the call. Subsequent\n    /// modifications of the path do not affect the [PathMetrics] object.\n    ///\n    /// Each path metric corresponds to a segment, or contour, of a path.\n    ///\n    /// For example, a path consisting of a [Path.lineTo], a [Path.moveTo], and\n    /// another [Path.lineTo] will contain two contours and thus be represented by\n    /// two [PathMetric] objects.\n    ///\n    /// When iterating across a [PathMetrics]' contours, the [PathMetric] objects are only\n    /// valid until the next one is obtained.\n    public class PathMetrics : List<PathMetric>\n    {\n        internal PathMetrics(Path path, bool forceClosed)\n        {\n            iterator = new PathMetricIterator(new PathMetric(path, forceClosed));\n        }\n\n        public IEnumerable<PathMetric> iterator { get; }\n    }\n\n    /// Tracks iteration from one segment of a path to the next for measurement.\n    public class PathMetricIterator : List<PathMetric>\n    {\n        internal PathMetricIterator(PathMetric _pathMetric)\n        {\n            this._pathMetric = _pathMetric;\n        }\n\n        PathMetric _pathMetric;\n        bool _firstTime = true;\n\n        public PathMetric current => _firstTime ? null : _pathMetric;\n\n        public bool moveNext()\n        {\n            // PathMetric isn't a normal iterable - it's already initialized to its\n            // first Path.  Should only call _moveNext when done with the first one.\n            if (_firstTime == true)\n            {\n                _firstTime = false;\n                return true;\n            }\n            else if (_pathMetric?._moveNext() == true)\n            {\n                return true;\n            }\n            _pathMetric = null;\n            return false;\n        }\n    }\n\n    /// Utilities for measuring a [Path] and extracting subpaths.\n    ///\n    /// Iterate over the object returned by [Path.computeMetrics] to obtain\n    /// [PathMetric] objects.\n    ///\n    /// Once created, metrics will only be valid while the iterator is at the given\n    /// contour. When the next contour's [PathMetric] is obtained, this object\n    /// becomes invalid.\n    public class PathMetric : NativePathMetric\n    {\n\n        /// Create a new empty [Path] object.\n        internal PathMetric(Path path, bool forceClosed) : base(path, forceClosed)\n        {\n\n        }\n\n        /// Return the total length of the current contour.\n        public double length => this.Length;\n\n        /// Computes the position of hte current contour at the given offset, and the\n        /// angle of the path at that point.\n        ///\n        /// For example, calling this method with a distance of 1.41 for a line from\n        /// 0.0,0.0 to 2.0,2.0 would give a point 1.0,1.0 and the angle 45 degrees\n        /// (but in radians).\n        ///\n        /// Returns null if the contour has zero [length].\n        ///\n        /// The distance is clamped to the [length] of the current contour.\n        public Tangent getTangentForOffset(double distance)\n        {\n            // first entry == 0 indicates that Skia returned false\n            SKPoint position = new SKPoint();\n            SKPoint tangent = new SKPoint();\n            if (this.GetPositionAndTangent((float)distance, out position, out tangent))\n            {\n                return null;\n            }\n            else\n            {\n                return new Tangent(\n                  new Offset(position.X, position.Y),\n                  new Offset(tangent.X, tangent.Y)\n                );\n            }\n        }\n\n        /// Given a start and stop distance, return the intervening segment(s).\n        ///\n        /// `start` and `end` are pinned to legal values (0..[length])\n        /// Returns null if the segment is 0 length or `start` > `stop`.\n        /// Begin the segment with a moveTo if `startWithMoveTo` is true.\n        public Path extractPath(double start, double end, bool startWithMoveTo = true)\n        {\n            Path path = new Path();\n            if (this.GetSegment((float)start, (float)end, path, startWithMoveTo))\n            {\n                return path;\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// Whether the contour is closed.\n        ///\n        /// Returns true if the contour ends with a call to [Path.close] (which may\n        /// have been implied when using [Path.addRect]) or if `forceClosed` was\n        /// specified as true in the call to [Path.computeMetrics].  Returns false\n        /// otherwise.\n        public bool isClosed => this.IsClosed;\n\n        // Move to the next contour in the path.\n        //\n        // A path can have a next contour if [Path.moveTo] was called after drawing began.\n        // Return true if one exists, or false.\n        //\n        // This is not exactly congruent with a regular [Iterator.moveNext].\n        // Typically, [Iterator.moveNext] should be called before accessing the\n        // [Iterator.current]. In this case, the [PathMetric] is valid before\n        // calling `_moveNext` - `_moveNext` should be called after the first\n        // iteration is done instead of before.\n        public bool _moveNext() => this.NextContour();\n    }\n\n    /// Styles to use for blurs in [MaskFilter] objects.\n    // These enum values must be kept in sync with SkBlurStyle.\n    public enum BlurStyle\n    {\n        // These mirror SkBlurStyle and must be kept in sync.\n\n        /// Fuzzy inside and outside. This is useful for painting shadows that are\n        /// offset from the shape that ostensibly is casting the shadow.\n        normal,\n\n        /// Solid inside, fuzzy outside. This corresponds to drawing the shape, and\n        /// additionally drawing the blur. This can make objects appear brighter,\n        /// maybe even as if they were fluorescent.\n        solid,\n\n        /// Nothing inside, fuzzy outside. This is useful for painting shadows for\n        /// partially transparent shapes, when they are painted separately but without\n        /// an offset, so that the shadow doesn't paint below the shape.\n        outer,\n\n        /// Fuzzy inside, nothing outside. This can make shapes appear to be lit from\n        /// within.\n        inner,\n    }\n\n    /// A mask filter to apply to shapes as they are painted. A mask filter is a\n    /// function that takes a bitmap of color pixels, and returns another bitmap of\n    /// color pixels.\n    ///\n    /// Instances of this class are used with [Paint.maskFilter] on [Paint] objects.\n    public class MaskFilter\n    {\n        /// Creates a mask filter that takes the shape being drawn and blurs it.\n        ///\n        /// This is commonly used to approximate shadows.\n        ///\n        /// The `style` argument controls the kind of effect to draw; see [BlurStyle].\n        ///\n        /// The `sigma` argument controls the size of the effect. It is the standard\n        /// deviation of the Gaussian blur to apply. The value must be greater than\n        /// zero. The sigma corresponds to very roughly half the radius of the effect\n        /// in pixels.\n        ///\n        /// A blur is an expensive operation and should therefore be used sparingly.\n        ///\n        /// The arguments must not be null.\n        ///\n        /// See also:\n        ///\n        ///  * [Canvas.drawShadow], which is a more efficient way to draw shadows.\n        public static MaskFilter blur(BlurStyle _style, double _sigma)\n        { //assert(_style != null),\n          //assert(_sigma != null);\n\n            return new MaskFilter(_style, _sigma);\n        }\n\n        private MaskFilter(BlurStyle style, double sigma)\n        {\n            _style = style;\n            _sigma = sigma;\n        }\n\n        public readonly BlurStyle _style;\n        public readonly double _sigma;\n\n        // The type of MaskFilter class to create for Skia.\n        // These constants must be kept in sync with MaskFilterType in paint.cc.\n        public const int _TypeNone = 0; // null\n        public const int _TypeBlur = 1; // SkBlurMaskFilter\n\n        public static bool operator ==(MaskFilter mask, Object other)\n        {\n            if (!(other is MaskFilter))\n                return false;\n            MaskFilter typedOther = (MaskFilter)other;\n            return mask._style == typedOther._style &&\n                   mask._sigma == typedOther._sigma;\n        }\n\n        public static bool operator !=(MaskFilter mask, Object other) => !(mask == other);\n\n        public int hashCode => hashValues(_style, _sigma);\n\n        public String toString() => $\"MaskFilter.blur({_style}, {_sigma.toStringAsFixed(1)})\";\n    }\n\n    /// A description of a color filter to apply when drawing a shape or compositing\n    /// a layer with a particular [Paint]. A color filter is a function that takes\n    /// two colors, and outputs one color. When applied during compositing, it is\n    /// independently applied to each pixel of the layer being drawn before the\n    /// entire layer is merged with the destination.\n    ///\n    /// Instances of this class are used with [Paint.colorFilter] on [Paint]\n    /// objects.\n    public class ColorFilter\n    {\n        /// Creates a color filter that applies the blend mode given as the second\n        /// argument. The source color is the one given as the first argument, and the\n        /// destination color is the one from the layer being composited.\n        ///\n        /// The output of this filter is then composited into the background according\n        /// to the [Paint.blendMode], using the output of this filter as the source\n        /// and the background as the destination.\n        public static ColorFilter mode(Color color, BlendMode blendMode)\n        {\n            return new ColorFilter(color, blendMode);\n        }\n\n        public ColorFilter(Color color, BlendMode blendMode)\n        {\n            _color = color;\n            _blendMode = blendMode;\n        }\n\n        public readonly Color _color;\n        public readonly BlendMode _blendMode;\n\n        public static bool operator ==(ColorFilter filter, Object other)\n        {\n            if (!(other is ColorFilter))\n                return false;\n            ColorFilter typedOther = (ColorFilter)other;\n            return filter._color == typedOther._color &&\n                   filter._blendMode == typedOther._blendMode;\n        }\n\n        public static bool operator !=(ColorFilter filter, Object other) => !(filter == other);\n\n        public int hashCode => hashValues(_color, _blendMode);\n\n        public String toString() => $\"ColorFilter({_color}, {_blendMode})\";\n    }\n\n    /// A filter operation to apply to a raster image.\n    ///\n    /// See also:\n    ///\n    ///  * [BackdropFilter], a widget that applies [ImageFilter] to its rendering.\n    ///  * [SceneBuilder.pushBackdropFilter], which is the low-level API for using\n    ///    this class.\n    public class ImageFilter : NativeFieldWrapperClass2\n    {\n        /// Creates an image filter that applies a Gaussian blur.\n        public static SKImageFilter blur(double sigmaX = 0.0, double sigmaY = 0.0)\n        {\n            return SKImageFilter.CreateBlur((float)sigmaX, (float)sigmaY);\n        }\n\n        /// Creates an image filter that applies a matrix transformation.\n        ///\n        /// For example, applying a positive scale matrix (see [new Matrix4.diagonal3])\n        /// when used with [BackdropFilter] would magnify the background image.\n        public static SKImageFilter matrix(List<float> matrix4,\n                          FilterQuality filterQuality = FilterQuality.low)\n        {\n            if (matrix4.Count != 16)\n                throw new ArgumentException(\"'matrix4' must have 16 entries.\");\n\n            return SKImageFilter.CreateMatrix(Matrix.ToSkMatrix(matrix4), (SKFilterQuality)filterQuality);\n        }\n\n    }\n\n    /// Defines what happens at the edge of the gradient.\n    ///\n    /// A gradient is defined along a finite inner area. In the case of a linear\n    /// gradient, it's between the parallel lines that are orthogonal to the line\n    /// drawn between two points. In the case of radial gradients, it's the disc\n    /// that covers the circle centered on a particular point up to a given radius.\n    ///\n    /// This enum is used to define how the gradient should paint the regions\n    /// outside that defined inner area.\n    ///\n    /// See also:\n    ///\n    ///  * [painting.Gradient], the superclass for [LinearGradient] and\n    ///    [RadialGradient], as used by [BoxDecoration] et al, which works in\n    ///    relative coordinates and can create a [Shader] representing the gradient\n    ///    for a particular [Rect] on demand.\n    ///  * [dart:ui.Gradient], the low-level class used when dealing with the\n    ///    [Paint.shader] property directly, with its [new Gradient.linear] and [new\n    ///    Gradient.radial] constructors.\n    // These enum values must be kept in sync with SkShader::TileMode.\n    public enum TileMode\n    {\n        /// Edge is clamped to the final color.\n        ///\n        /// The gradient will paint the all the regions outside the inner area with\n        /// the color of the point closest to that region.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_radial.png)\n        clamp,\n\n        /// Edge is repeated from first color to last.\n        ///\n        /// This is as if the stop points from 0.0 to 1.0 were then repeated from 1.0\n        /// to 2.0, 2.0 to 3.0, and so forth (and for linear gradients, similarly from\n        /// -1.0 to 0.0, -2.0 to -1.0, etc).\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_linear.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_radial.png)\n        repeated,\n\n        /// Edge is mirrored from last color to first.\n        ///\n        /// This is as if the stop points from 0.0 to 1.0 were then repeated backwards\n        /// from 2.0 to 1.0, then forwards from 2.0 to 3.0, then backwards again from\n        /// 4.0 to 3.0, and so forth (and for linear gradients, similarly from in the\n        /// negative direction).\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_linear.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_radial.png)\n        mirror,\n    }\n\n\n\n    /// A shader (as used by [Paint.shader]) that renders a color gradient.\n    ///\n    /// There are several types of gradients, represented by the various constructors\n    /// on this class.\n    public class Gradient\n    {\n\n        /// Creates a linear gradient from `from` to `to`.\n        ///\n        /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0\n        /// that specifies where `color[i]` begins in the gradient. If `colorStops` is\n        /// not provided, then only two stops, at 0.0 and 1.0, are implied (and\n        /// `color` must therefore only have two entries).\n        ///\n        /// The behavior before `from` and after `to` is described by the `tileMode`\n        /// argument. For details, see the [TileMode] enum.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_linear.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_linear.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_linear.png)\n        ///\n        /// If `from`, `to`, `colors`, or `tileMode` are null, or if `colors` or\n        /// `colorStops` contain null values, this constructor will throw a\n        /// [NoSuchMethodError].\n        public static SKShader linear(\n        Offset from,\n        Offset to,\n        List<Color> colors,\n        List<double> colorStops = null,\n        TileMode tileMode = TileMode.clamp)\n        {\n            //assert(_offsetIsValid(from)),\n            //assert(_offsetIsValid(to)),\n            //assert(colors != null),\n            //assert(tileMode != null),\n\n            return SKShader.CreateLinearGradient(from.ToPoint(), to.ToPoint(), colors.ToColors().ToArray(), colorStops.Cast<float>().ToArray(), (SKShaderTileMode)tileMode);\n        }\n\n        /// Creates a radial gradient centered at `center` that ends at `radius`\n        /// distance from the center.\n        ///\n        /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0\n        /// that specifies where `color[i]` begins in the gradient. If `colorStops` is\n        /// not provided, then only two stops, at 0.0 and 1.0, are implied (and\n        /// `color` must therefore only have two entries).\n        ///\n        /// The behavior before and after the radius is described by the `tileMode`\n        /// argument. For details, see the [TileMode] enum.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_radial.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_radial.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_radial.png)\n        ///\n        /// If `center`, `radius`, `colors`, or `tileMode` are null, or if `colors` or\n        /// `colorStops` contain null values, this constructor will throw a\n        /// [NoSuchMethodError].\n        ///\n        /// If `matrix4` is provided, the gradient fill will be transformed by the\n        /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must\n        /// be a column-major matrix packed into a list of 16 values.\n        ///\n        /// If `focal` is provided and not equal to `center` and `focalRadius` is\n        /// provided and not equal to 0.0, the generated shader will be a two point\n        /// conical radial gradient, with `focal` being the center of the focal\n        /// circle and `focalRadius` being the radius of that circle. If `focal` is\n        /// provided and not equal to `center`, at least one of the two offsets must\n        /// not be equal to [Offset.zero].\n        public static SKShader radial(\n        Offset center,\n        double radius,\n        List<Color> colors,\n        List<double> colorStops = null,\n        TileMode tileMode = TileMode.clamp,\n        List<float> matrix4 = null,\n        Offset focal = null,\n        double focalRadius = 0.0)\n        {\n            //assert(_offsetIsValid(center)),\n            //assert(colors != null),\n            //assert(tileMode != null),\n            //assert(matrix4 == null || _matrix4IsValid(matrix4)),\n\n            _validateColorStops(colors, colorStops);\n            //List<uint> colorsBuffer = _encodeColorList(colors);\n            List<double> colorStopsBuffer = colorStops == null ? null : new List<double>(colorStops);\n\n            // If focal is null or focal radius is null, this should be treated as a regular radial gradient\n            // If focal == center and the focal radius is 0.0, it's still a regular radial gradient\n            if (focal == null || (focal == center && focalRadius == 0.0))\n            {\n                return SKShader.CreateRadialGradient(center.ToPoint(), (float)radius, colors.ToColors().ToArray(), colorStopsBuffer.Cast<float>().ToArray(), (SKShaderTileMode)tileMode, Matrix.ToSkMatrix(matrix4));\n            }\n            else\n            {\n                return SKShader.CreateTwoPointConicalGradient(focal.ToPoint(), (float)focalRadius, center.ToPoint(), (float)radius, colors.ToColors().ToArray(), colorStopsBuffer.Cast<float>().ToArray(), (SKShaderTileMode)tileMode, Matrix.ToSkMatrix(matrix4));\n            }\n        }\n\n\n        /// Creates a sweep gradient centered at `center` that starts at `startAngle`\n        /// and ends at `endAngle`.\n        ///\n        /// `startAngle` and `endAngle` should be provided in radians, with zero\n        /// radians being the horizontal line to the right of the `center` and with\n        /// positive angles going clockwise around the `center`.\n        ///\n        /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0\n        /// that specifies where `color[i]` begins in the gradient. If `colorStops` is\n        /// not provided, then only two stops, at 0.0 and 1.0, are implied (and\n        /// `color` must therefore only have two entries).\n        ///\n        /// The behavior before `startAngle` and after `endAngle` is described by the\n        /// `tileMode` argument. For details, see the [TileMode] enum.\n        ///\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_clamp_sweep.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_mirror_sweep.png)\n        /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_sweep.png)\n        ///\n        /// If `center`, `colors`, `tileMode`, `startAngle`, or `endAngle` are null,\n        /// or if `colors` or `colorStops` contain null values, this constructor will\n        /// throw a [NoSuchMethodError].\n        ///\n        /// If `matrix4` is provided, the gradient fill will be transformed by the\n        /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must\n        /// be a column-major matrix packed into a list of 16 values.\n        public static SKShader sweep(\n        Offset center,\n        List<Color> colors,\n        List<double> colorStops = null,\n        TileMode tileMode = TileMode.clamp,\n        double startAngle = 0.0,\n        double endAngle = Math.PI * 2,\n        List<float> matrix4 = null)\n        {\n            //assert(_offsetIsValid(center)),\n            //assert(colors != null),\n            //assert(tileMode != null),\n            //assert(startAngle != null),\n            //assert(endAngle != null),\n            //assert(startAngle<endAngle),\n            //assert(matrix4 == null || _matrix4IsValid(matrix4)),\n\n            _validateColorStops(colors, colorStops);\n            List<uint> colorsBuffer = _encodeColorList(colors);\n            List<double> colorStopsBuffer = colorStops == null ? null : new List<double>(colorStops);\n            return SKShader.CreateSweepGradient(center.ToPoint(), colors.ToColors().ToArray(), colorStopsBuffer.Cast<float>().ToArray(), Matrix.ToSkMatrix(matrix4));\n        }\n\n        static void _validateColorStops(List<Color> colors, List<double> colorStops)\n        {\n            if (colorStops == null)\n            {\n                if (colors.Count != 2)\n                    throw new ArgumentException(\"'colors' must have length 2 if 'colorStops' is omitted.\");\n            }\n            else\n            {\n                if (colors.Count != colorStops.Count)\n                    throw new ArgumentException(\"'colors' and 'colorStops' arguments must have equal length.\");\n            }\n        }\n    }\n\n    /// A shader (as used by [Paint.shader]) that tiles an image.\n    public class ImageShader\n    {\n        /// Creates an image-tiling shader. The first argument specifies the image to\n        /// tile. The second and third arguments specify the [TileMode] for the x\n        /// direction and y direction respectively. The fourth argument gives the\n        /// matrix to apply to the effect. All the arguments are required and must not\n        /// be null.\n        public static SKShader ToImageShader(SKImage image, TileMode tmx, TileMode tmy, List<double> matrix4)\n        {\n            //assert(image != null), // image is checked on the engine side\n            //assert(tmx != null),\n            //assert(tmy != null),\n            //assert(matrix4 != null),\n            if (matrix4.Count != 16)\n                throw new ArgumentException(\"'matrix4' must have 16 entries.\");\n\n            return image.ToShader((SKShaderTileMode)tmx, (SKShaderTileMode)tmy, Matrix.ToSkMatrix(matrix4));\n        }\n    }\n\n    /// Defines how a list of points is interpreted when drawing a set of triangles.\n    ///\n    /// Used by [Canvas.drawVertices].\n    // These enum values must be kept in sync with SkVertices::VertexMode.\n    public enum VertexMode\n    {\n        /// Draw each sequence of three points as the vertices of a triangle.\n        triangles,\n\n        /// Draw each sliding window of three points as the vertices of a triangle.\n        triangleStrip,\n\n        /// Draw the first point and each sliding window of two points as the vertices of a triangle.\n        triangleFan,\n    }\n\n    /// A set of vertex data used by [Canvas.drawVertices].\n    public class Vertices\n    {\n        public static SKVertices Raw(\n            VertexMode mode,\n            List<Offset> positions,\n            List<Offset> textureCoordinates = null,\n            List<Color> colors = null,\n            List<int> indices = null)\n        {\n            //assert(mode != null),\n            //assert(positions != null)\n            if (textureCoordinates != null && textureCoordinates.Count != positions.Count)\n                throw new ArgumentException(\"'positions' and 'textureCoordinates' lengths must match.\");\n            if (colors != null && colors.Count != positions.Count)\n                throw new ArgumentException(\"'positions' and 'colors' lengths must match.\");\n            if (indices != null && indices.Any((int i) => i < 0 || i >= positions.Count))\n                throw new ArgumentException(\"'indices' values must be valid indices in the positions list.\");\n\n\n            var positionList = new List<SKPoint>();\n            foreach (var p in positions)\n                positionList.Add(p.ToPoint());\n\n            var textureList = new List<SKPoint>();\n            foreach (var t in textureCoordinates)\n                textureList.Add(t.ToPoint());\n\n            return SKVertices.CreateCopy((SKVertexMode)mode, positionList.ToArray(), textureList.ToArray(), colors.ToColors().ToArray(), indices.Cast<ushort>().ToArray());\n        }\n    }\n\n    /// Defines how a list of points is interpreted when drawing a set of points.\n    ///\n    // ignore: deprecated_member_use\n    /// Used by [Canvas.drawPoints].\n    // These enum values must be kept in sync with SKCanvas::PointMode.\n    public enum PointMode\n    {\n        /// Draw each point separately.\n        ///\n        /// If the [Paint.strokeCap] is [StrokeCap.round], then each point is drawn\n        /// as a circle with the diameter of the [Paint.strokeWidth], filled as\n        /// described by the [Paint] (ignoring [Paint.style]).\n        ///\n        /// Otherwise, each point is drawn as an axis-aligned square with sides of\n        /// length [Paint.strokeWidth], filled as described by the [Paint] (ignoring\n        /// [Paint.style]).\n        points,\n\n        /// Draw each sequence of two points as a line segment.\n        ///\n        /// If the number of points is odd, then the last point is ignored.\n        ///\n        /// The lines are stroked as described by the [Paint] (ignoring\n        /// [Paint.style]).\n        lines,\n\n        /// Draw the entire sequence of point as one line.\n        ///\n        /// The lines are stroked as described by the [Paint] (ignoring\n        /// [Paint.style]).\n        polygon,\n    }\n\n    /// Defines how a new clip region should be merged with the existing clip\n    /// region.\n    ///\n    /// Used by [Canvas.clipRect].\n    public enum ClipOp\n    {\n        /// Subtract the new region from the existing region.\n        difference,\n\n        /// Intersect the new region from the existing region.\n        intersect,\n    }\n\n    /// An interface for recording graphical operations.\n    ///\n    /// [Canvas] objects are used in creating [Picture] objects, which can\n    /// themselves be used with a [SceneBuilder] to build a [Scene]. In\n    /// normal usage, however, this is all handled by the framework.\n    ///\n    /// A canvas has a current transformation matrix which is applied to all\n    /// operations. Initially, the transformation matrix is the identity transform.\n    /// It can be modified using the [translate], [scale], [rotate], [skew],\n    /// and [transform] methods.\n    ///\n    /// A canvas also has a current clip region which is applied to all operations.\n    /// Initially, the clip region is infinite. It can be modified using the\n    /// [clipRect], [clipRRect], and [clipPath] methods.\n    ///\n    /// The current transform and clip can be saved and restored using the stack\n    /// managed by the [save], [saveLayer], and [restore] methods.\n    public class Canvas : NativeCanvas, ICanvas\n    {\n        /// Creates a canvas for recording graphical operations into the\n        /// given picture recorder.\n        ///\n        /// Graphical operations that affect pixels entirely outside the given\n        /// `cullRect` might be discarded by the implementation. However, the\n        /// implementation might draw outside these bounds if, for example, a command\n        /// draws partially inside and outside the `cullRect`. To ensure that pixels\n        /// outside a given region are discarded, consider using a [clipRect]. The\n        /// `cullRect` is optional; by default, all operations are kept.\n        ///\n        /// To end the recording, call [PictureRecorder.endRecording] on the\n        /// given recorder.\n        public Canvas(PictureRecorder recorder, Rect cullRect = null) : base(new SKBitmap()) //: //assert(recorder != null)\n        {\n            if (recorder.isRecording)\n                throw new ArgumentException(\"'recorder' must not already be associated with another Canvas.\");\n            if (cullRect == null)\n                cullRect = Rect.largest;\n            _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom);\n        }\n        void _constructor(PictureRecorder recorder,\n                          double left,\n                          double top,\n                          double right,\n                          double bottom)\n        {\n            this.Constructor(recorder, left, top, right, bottom);\n            // [DONE] native 'Canvas_constructor';\n        }\n\n        /// Saves a copy of the current transform and clip on the save stack.\n        ///\n        /// Call [restore] to pop the save stack.\n        ///\n        /// See also:\n        ///\n        ///  * [saveLayer], which does the same thing but additionally also groups the\n        ///    commands done until the matching [restore].\n        public void Save() => this.Save();\n\n        /// Saves a copy of the current transform and clip on the save stack, and then\n        /// creates a new group which subsequent calls will become a part of. When the\n        /// save stack is later popped, the group will be flattened into a layer and\n        /// have the given `paint`'s [Paint.colorFilter] and [Paint.blendMode]\n        /// applied.\n        ///\n        /// This lets you create composite effects, for example making a group of\n        /// drawing commands semi-transparent. Without using [saveLayer], each part of\n        /// the group would be painted individually, so where they overlap would be\n        /// darker than where they do not. By using [saveLayer] to group them\n        /// together, they can be drawn with an opaque color at first, and then the\n        /// entire group can be made transparent using the [saveLayer]'s paint.\n        ///\n        /// Call [restore] to pop the save stack and apply the paint to the group.\n        ///\n        /// ## Using saveLayer with clips\n        ///\n        /// When a rectangular clip operation (from [clipRect]) is not axis-aligned\n        /// with the raster buffer, or when the clip operation is not rectalinear (e.g.\n        /// because it is a rounded rectangle clip created by [clipRRect] or an\n        /// arbitrarily complicated path clip created by [clipPath]), the edge of the\n        /// clip needs to be anti-aliased.\n        ///\n        /// If two draw calls overlap at the edge of such a clipped region, without\n        /// using [saveLayer], the first drawing will be anti-aliased with the\n        /// background first, and then the second will be anti-aliased with the result\n        /// of blending the first drawing and the background. On the other hand, if\n        /// [saveLayer] is used immediately after establishing the clip, the second\n        /// drawing will cover the first in the layer, and thus the second alone will\n        /// be anti-aliased with the background when the layer is clipped and\n        /// composited (when [restore] is called).\n        ///\n        /// For example, this [CustomPainter.paint] method paints a clean white\n        /// rounded rectangle:\n        ///\n        /// ```dart\n        /// void paint(Canvas canvas, Size size) {\n        ///   Rect rect = Offset.zero & size;\n        ///   canvas.save();\n        ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));\n        ///   canvas.saveLayer(rect, new Paint());\n        ///   canvas.drawPaint(new Paint()..color = Colors.red);\n        ///   canvas.drawPaint(new Paint()..color = Colors.white);\n        ///   canvas.restore();\n        ///   canvas.restore();\n        /// }\n        /// ```\n        ///\n        /// On the other hand, this one renders a red outline, the result of the red\n        /// paint being anti-aliased with the background at the clip edge, then the\n        /// white paint being similarly anti-aliased with the background _including\n        /// the clipped red paint_:\n        ///\n        /// ```dart\n        /// void paint(Canvas canvas, Size size) {\n        ///   // (this example renders poorly, prefer the example above)\n        ///   Rect rect = Offset.zero & size;\n        ///   canvas.save();\n        ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));\n        ///   canvas.drawPaint(new Paint()..color = Colors.red);\n        ///   canvas.drawPaint(new Paint()..color = Colors.white);\n        ///   canvas.restore();\n        /// }\n        /// ```\n        ///\n        /// This point is moot if the clip only clips one draw operation. For example,\n        /// the following paint method paints a pair of clean white rounded\n        /// rectangles, even though the clips are not done on a separate layer:\n        ///\n        /// ```dart\n        /// void paint(Canvas canvas, Size size) {\n        ///   canvas.save();\n        ///   canvas.clipRRect(new RRect.fromRectXY(Offset.zero & (size / 2.0), 50.0, 50.0));\n        ///   canvas.drawPaint(new Paint()..color = Colors.white);\n        ///   canvas.restore();\n        ///   canvas.save();\n        ///   canvas.clipRRect(new RRect.fromRectXY(size.center(Offset.zero) & (size / 2.0), 50.0, 50.0));\n        ///   canvas.drawPaint(new Paint()..color = Colors.white);\n        ///   canvas.restore();\n        /// }\n        /// ```\n        ///\n        /// (Incidentally, rather than using [clipRRect] and [drawPaint] to draw\n        /// rounded rectangles like this, prefer the [drawRRect] method. These\n        /// examples are using [drawPaint] as a proxy for \"complicated draw operations\n        /// that will get clipped\", to illustrate the point.)\n        ///\n        /// ## Performance considerations\n        ///\n        /// Generally speaking, [saveLayer] is relatively expensive.\n        ///\n        /// There are a several different hardware architectures for GPUs (graphics\n        /// processing units, the hardware that handles graphics), but most of them\n        /// involve batching commands and reordering them for performance. When layers\n        /// are used, they cause the rendering pipeline to have to switch render\n        /// target (from one layer to another). Render target switches can flush the\n        /// GPU's command buffer, which typically means that optimizations that one\n        /// could get with larger batching are lost. Render target switches also\n        /// generate a lot of memory churn because the GPU needs to copy out the\n        /// current frame buffer contents from the part of memory that's optimized for\n        /// writing, and then needs to copy it back in once the previous render target\n        /// (layer) is restored.\n        ///\n        /// See also:\n        ///\n        ///  * [save], which saves the current state, but does not create a new layer\n        ///    for subsequent commands.\n        ///  * [BlendMode], which discusses the use of [Paint.blendMode] with\n        ///    [saveLayer].\n        void saveLayer(Rect bounds, SKPaint paint)\n        {\n            ////assert(paint != null);\n            if (bounds == null)\n            {\n                this.SaveLayer(paint);\n            }\n            else\n            {\n                //assert(_rectIsValid(bounds));\n                this.SaveLayer(bounds.ToRect(), paint);\n            }\n        }\n\n        /// Pops the current save stack, if there is anything to pop.\n        /// Otherwise, does nothing.\n        ///\n        /// Use [save] and [saveLayer] to push state onto the stack.\n        ///\n        /// If the state was pushed with with [saveLayer], then this call will also\n        /// cause the new layer to be composited into the previous layer.\n        public void Restore()\n        {\n            // [DONE] native 'Canvas_restore';\n            this.Restore();\n        }\n\n        /// Returns the number of items on the save stack, including the\n        /// initial state. This means it returns 1 for a clean canvas, and\n        /// that each call to [save] and [saveLayer] increments it, and that\n        /// each matching call to [restore] decrements it.\n        ///\n        /// This number cannot go below 1.\n        public int GetSaveCount() => this.SaveCount;\n\n        /// Add a translation to the current transform, shifting the coordinate space\n        /// horizontally by the first argument and vertically by the second argument.\n        public void Translate(double dx, double dy) => this.Translate((float)dx, (float)dy);\n\n        /// Add an axis-aligned scale to the current transform, scaling by the first\n        /// argument in the horizontal direction and the second in the vertical\n        /// direction.\n        ///\n        /// If [sy] is unspecified, [sx] will be used for the scale in both\n        /// directions.\n        public void Scale(double sx, double sy = default(double)) => _scale(sx, sy);\n\n        void _scale(double sx, double sy)\n        {\n            RecordingCanvas.Scale((float)sx, (float)sy);\n            // [DONE] native 'Canvas_scale';\n        }\n\n        /// Add a rotation to the current transform. The argument is in radians clockwise.\n        public void Rotate(double radians)\n        {\n            this.RotateRadians((float)radians);\n        }\n\n        /// Add an axis-aligned skew to the current transform, with the first argument\n        /// being the horizontal skew in radians clockwise around the origin, and the\n        /// second argument being the vertical skew in radians clockwise around the\n        /// origin.\n        public void Skew(double sx, double sy)\n        {\n            this.Skew((float)sx, (float)sy);\n        }\n\n        /// Multiply the current transform by the specified 4⨉4 transformation matrix\n        /// specified as a list of values in column-major order.\n        public void Transform(List<float> matrix4)\n        {\n            ////assert(matrix4 != null);\n            if (matrix4.Count != 16)\n                throw new ArgumentException(\"'matrix4' must have 16 entries.\");\n            _transform(matrix4);\n        }\n        void _transform(List<float> matrix4)\n        {\n            var matrix = Matrix.ToSkMatrix(matrix4);\n            this.Concat(ref matrix);\n        }\n\n        /// Reduces the clip region to the intersection of the current clip and the\n        /// given rectangle.\n        ///\n        /// If [doAntiAlias] is true, then the clip will be anti-aliased.\n        ///\n        /// If multiple draw commands intersect with the clip boundary, this can result\n        /// in incorrect blending at the clip boundary. See [saveLayer] for a\n        /// discussion of how to address that.\n        ///\n        /// Use [ClipOp.difference] to subtract the provided rectangle from the\n        /// current clip.\n        public void ClipRect(Rect rect, ClipOp clipOp = default(ClipOp), bool doAntiAlias = true)\n        {\n            ////assert(_rectIsValid(rect));\n            ////assert(clipOp != null);\n            ////assert(doAntiAlias != null);\n\n            this.ClipRect(rect.ToRect(), (SKClipOperation)clipOp, doAntiAlias);\n        }\n\n        /// Reduces the clip region to the intersection of the current clip and the\n        /// given rounded rectangle.\n        ///\n        /// If [doAntiAlias] is true, then the clip will be anti-aliased.\n        ///\n        /// If multiple draw commands intersect with the clip boundary, this can result\n        /// in incorrect blending at the clip boundary. See [saveLayer] for a\n        /// discussion of how to address that and some examples of using [clipRRect].\n        public void ClipRRect(RRect rrect, bool doAntiAlias = true)\n        {\n            ////assert(_rrectIsValid(rrect));\n            ////assert(doAntiAlias != null);\n            this.ClipRoundRect(rrect.ToRoundedRect(), antialias: doAntiAlias);\n        }\n\n        /// Reduces the clip region to the intersection of the current clip and the\n        /// given [Path].\n        ///\n        /// If [doAntiAlias] is true, then the clip will be anti-aliased.\n        ///\n        /// If multiple draw commands intersect with the clip boundary, this can result\n        /// multiple draw commands intersect with the clip boundary, this can result\n        /// in incorrect blending at the clip boundary. See [saveLayer] for a\n        /// discussion of how to address that.\n        public void ClipPath(Path path, bool doAntiAlias = true)\n        {\n            ////assert(path != null); // path is checked on the engine side\n            ////assert(doAntiAlias != null);\n            this.ClipPath(path, antialias: doAntiAlias);\n        }\n\n        /// Paints the given [Color] onto the canvas, applying the given\n        /// [BlendMode], with the given color being the source and the background\n        /// being the destination.\n        public void DrawColor(Color color, BlendMode blendMode)\n        {\n            ////assert(color != null);\n            ////assert(blendMode != null);\n            this.DrawColor(new SKColor(color.value), (SKBlendMode)blendMode);\n        }\n\n        /// Draws a line between the given points using the given paint. The line is\n        /// stroked, the value of the [Paint.style] is ignored for this call.\n        ///\n        /// The `p1` and `p2` arguments are interpreted as offsets from the origin.\n        public void DrawLine(Offset p1, Offset p2, SKPaint paint)\n        {\n            ////assert(_offsetIsValid(p1));\n            ////assert(_offsetIsValid(p2));\n            ////assert(paint != null);\n\n            this.DrawLine(p1.ToPoint(), p2.ToPoint(), paint);\n\n        }\n\n        /// Fills the canvas with the given [Paint].\n        ///\n        /// To fill the canvas with a solid color and blend mode, consider\n        /// [drawColor] instead.\n        public void DrawPaint(SKPaint paint)\n        {\n            //assert(paint != null);\n            this.DrawPaint(paint);\n        }\n\n        /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled\n        /// or stroked (or both) is controlled by [Paint.style].\n        void drawRect(Rect rect, SKPaint paint)\n        {\n            //assert(_rectIsValid(rect));\n            //assert(paint != null);\n            this.DrawRect(rect.ToRect(), paint);\n        }\n\n        /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is\n        /// filled or stroked (or both) is controlled by [Paint.style].\n        void drawRRect(RRect rrect, SKPaint paint)\n        {\n            //assert(_rrectIsValid(rrect));\n            //assert(paint != null);\n            this.DrawRoundRect(rrect.ToRoundedRect(), paint);\n        }\n\n        /// Draws a shape consisting of the difference between two rounded rectangles\n        /// with the given [Paint]. Whether this shape is filled or stroked (or both)\n        /// is controlled by [Paint.style].\n        ///\n        /// This shape is almost but not quite entirely unlike an annulus.\n        void drawDRRect(RRect outer, RRect inner, Paint paint)\n        {\n            //assert(_rrectIsValid(outer));\n            //assert(_rrectIsValid(inner));\n            //assert(paint != null);\n\n            // TODO: Missing SkiaSharp reference\n            // native 'Canvas_drawDRRect';\n        }\n\n        /// Draws an axis-aligned oval that fills the given axis-aligned rectangle\n        /// with the given [Paint]. Whether the oval is filled or stroked (or both) is\n        /// controlled by [Paint.style].\n        void drawOval(Rect rect, SKPaint paint)\n        {\n            //assert(_rectIsValid(rect));\n            //assert(paint != null);\n            this.DrawOval(rect.ToRect(), paint);\n        }\n\n        /// Draws a circle centered at the point given by the first argument and\n        /// that has the radius given by the second argument, with the [Paint] given in\n        /// the third argument. Whether the circle is filled or stroked (or both) is\n        /// controlled by [Paint.style].\n        void drawCircle(Offset c, double radius, SKPaint paint)\n        {\n            //assert(_offsetIsValid(c));\n            //assert(paint != null);\n            this.DrawCircle(c.ToPoint(), (float)radius, paint);\n        }\n\n        /// Draw an arc scaled to fit inside the given rectangle. It starts from\n        /// startAngle radians around the oval up to startAngle + sweepAngle\n        /// radians around the oval, with zero radians being the point on\n        /// the right hand side of the oval that crosses the horizontal line\n        /// that intersects the center of the rectangle and with positive\n        /// angles going clockwise around the oval. If useCenter is true, the arc is\n        /// closed back to the center, forming a circle sector. Otherwise, the arc is\n        /// not closed, forming a circle segment.\n        ///\n        /// This method is optimized for drawing arcs and should be faster than [Path.arcTo].\n        void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)\n        {\n            //assert(_rectIsValid(rect));\n            //assert(paint != null);\n\n            // TODO: not implemented on SkiaSharp\n            // native 'Canvas_drawArc';\n        }\n\n        /// Draws the given [Path] with the given [Paint]. Whether this shape is\n        /// filled or stroked (or both) is controlled by [Paint.style]. If the path is\n        /// filled, then subpaths within it are implicitly closed (see [Path.close]).\n        void drawPath(Path path, SKPaint paint)\n        {\n            //assert(path != null); // path is checked on the engine side\n            //assert(paint != null);\n            this.DrawPath(path, paint);\n        }\n\n        /// Draws the given [Image] into the canvas with its top-left corner at the\n        /// given [Offset]. The image is composited into the canvas using the given [Paint].\n        void drawImage(SKImage image, Offset p, SKPaint paint)\n        {\n            //assert(image != null); // image is checked on the engine side\n            //assert(_offsetIsValid(p));\n            //assert(paint != null);\n            this.DrawImage(image, p.ToPoint(), paint);\n        }\n\n        /// Draws the subset of the given image described by the `src` argument into\n        /// the canvas in the axis-aligned rectangle given by the `dst` argument.\n        ///\n        /// This might sample from outside the `src` rect by up to half the width of\n        /// an applied filter.\n        ///\n        /// Multiple calls to this method with different arguments (from the same\n        /// image) can be batched into a single call to [drawAtlas] to improve\n        /// performance.\n        void drawImageRect(SKImage image, Rect src, Rect dst, SKPaint paint)\n        {\n            //assert(image != null); // image is checked on the engine side\n            //assert(_rectIsValid(src));\n            //assert(_rectIsValid(dst));\n            //assert(paint != null);\n            this.DrawImage(image, src.ToRect(), dst.ToRect(), paint);\n\n        }\n\n        /// Draws the given [Image] into the canvas using the given [Paint].\n        ///\n        /// The image is drawn in nine portions described by splitting the image by\n        /// drawing two horizontal lines and two vertical lines, where the `center`\n        /// argument describes the rectangle formed by the four points where these\n        /// four lines intersect each other. (This forms a 3-by-3 grid of regions,\n        /// the center region being described by the `center` argument.)\n        ///\n        /// The four regions in the corners are drawn, without scaling, in the four\n        /// corners of the destination rectangle described by `dst`. The remaining\n        /// five regions are drawn by stretching them to fit such that they exactly\n        /// cover the destination rectangle while maintaining their relative\n        /// positions.\n        public void DrawImageNine(SKImage image, Rect center, Rect dst, SKPaint paint)\n        {\n            //assert(image != null); // image is checked on the engine side\n            //assert(_rectIsValid(center));\n            //assert(_rectIsValid(dst));\n            //assert(paint != null);\n            this.DrawImageNinePatch(image, center.ToRectI(), dst.ToRect(), paint);\n\n        }\n\n\n        /// Draw the given picture onto the canvas. To create a picture, see\n        /// [PictureRecorder].\n        public void DrawPicture(SKPicture picture)\n        {\n            //assert(picture != null); // picture is checked on the engine side        \n            this.DrawPicture(picture);\n        }\n\n        /// Draws the text in the given [Paragraph] into this canvas at the given\n        /// [Offset].\n        ///\n        /// The [Paragraph] object must have had [Paragraph.layout] called on it\n        /// first.\n        ///\n        /// To align the text, set the `textAlign` on the [ParagraphStyle] object\n        /// passed to the [new ParagraphBuilder] constructor. For more details see\n        /// [TextAlign] and the discussion at [new ParagraphStyle].\n        ///\n        /// If the text is left aligned or justified, the left margin will be at the\n        /// position specified by the `offset` argument's [Offset.dx] coordinate.\n        ///\n        /// If the text is right aligned or justified, the right margin will be at the\n        /// position described by adding the [ParagraphConstraints.width] given to\n        /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.\n        ///\n        /// If the text is centered, the centering axis will be at the position\n        /// described by adding half of the [ParagraphConstraints.width] given to\n        /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.\n        public void DrawParagraph(Paragraph paragraph, Offset offset)\n        {\n            //assert(paragraph != null);\n            //assert(_offsetIsValid(offset));\n            paragraph._paint(RecordingCanvas, offset.dx, offset.dy);\n        }\n\n        /// Draws a sequence of points according to the given [PointMode].\n        ///\n        /// The `points` argument is interpreted as offsets from the origin.\n        ///\n        /// See also:\n        ///\n        ///  * [drawRawPoints], which takes `points` as a [List<float> ] rather than a\n        ///    [List<Offset>].\n        public void DrawPoints(PointMode pointMode, List<Offset> points, SKPaint paint)\n        {\n            //assert(pointMode != null);\n            //assert(points != null);\n            //assert(paint != null);\n            this.DrawPoints((SKPointMode)pointMode, points.ToPoints().ToArray(), paint);\n        }\n\n        /// Draws a sequence of points according to the given [PointMode].\n        ///\n        /// The `points` argument is interpreted as a list of pairs of floating point\n        /// numbers, where each pair represents an x and y offset from the origin.\n        ///\n        /// See also:\n        ///\n        ///  * [drawPoints], which takes `points` as a [List<Offset>] rather than a\n        ///    [List<List<float> >].\n        public void DrawRawPoints(PointMode pointMode, List<double> points, SKPaint paint)\n        {\n            //assert(pointMode != null);\n            //assert(points != null);\n            //assert(paint != null);\n            if (points.Count % 2 != 0)\n                throw new ArgumentException(\"'points' must have an even number of values.\");\n\n            var list = new List<Offset>();\n            for (int i = 0; i < points.Count; i = i + 2)\n            {\n                list.Add(new Offset(points[i], points[i + 1]));\n            }\n\n            DrawPoints(pointMode, list, paint);\n        }\n\n\n\n        public void DrawVertices(SKVertices vertices, BlendMode blendMode, SKPaint paint)\n        {\n            //assert(vertices != null); // vertices is checked on the engine side\n            //assert(paint != null);\n            //assert(blendMode != null);\n            this.DrawVertices(vertices, (SKBlendMode)blendMode, paint);\n        }       \n\n        //\n        // See also:\n        //\n        //  * [drawRawAtlas], which takes its arguments as typed data lists rather\n        //    than objects.\n        void drawAtlas(SKImage atlas,\n                       List<RSTransform> transforms,\n                       List<Rect> rects,\n                       List<Color> colors,\n                       BlendMode blendMode,\n                       Rect cullRect,\n                       Paint paint)\n        {\n            //assert(atlas != null); // atlas is checked on the engine side\n            //assert(transforms != null);\n            //assert(rects != null);\n            //assert(colors != null);\n            //assert(blendMode != null);\n            //assert(paint != null);\n\n            int rectCount = rects.Count;\n            if (transforms.Count != rectCount)\n                throw new ArgumentException(\"'transforms' and 'rects' lengths must match.\");\n            if (colors.Count > 0 && colors.Count != rectCount)\n                throw new ArgumentException(\"'If non-null, 'colors' length must match that of 'transforms' and 'rects'.\");\n\n            List<double> rstTransformBuffer = new List<double>(rectCount * 4);\n            List<double> rectBuffer = new List<double>(rectCount * 4);\n\n            for (int i = 0; i < rectCount; ++i)\n            {\n                int index0 = i * 4;\n                int index1 = index0 + 1;\n                int index2 = index0 + 2;\n                int index3 = index0 + 3;\n                RSTransform rstTransform = transforms[i];\n                Rect rect = rects[i];\n                //assert(_rectIsValid(rect));\n                rstTransformBuffer[index0] = rstTransform.scos;\n                rstTransformBuffer[index1] = rstTransform.ssin;\n                rstTransformBuffer[index2] = rstTransform.tx;\n                rstTransformBuffer[index3] = rstTransform.ty;\n                rectBuffer[index0] = rect.left;\n                rectBuffer[index1] = rect.top;\n                rectBuffer[index2] = rect.right;\n                rectBuffer[index3] = rect.bottom;\n            }\n\n            List<uint> colorBuffer = colors.Count == 0 ? null : _encodeColorList(colors);\n            List<double> cullRectBuffer = cullRect?._value;\n            \n            _drawAtlas( \n              paint._objects, paint._data, atlas, rstTransformBuffer, rectBuffer,\n              colorBuffer, (int)blendMode, cullRectBuffer\n            );\n        }\n\n        //\n        // The `rstTransforms` argument is interpreted as a list of four-tuples, with\n        // each tuple being ([RSTransform.scos], [RSTransform.ssin],\n        // [RSTransform.tx], [RSTransform.ty]).\n        //\n        // The `rects` argument is interpreted as a list of four-tuples, with each\n        // tuple being ([Rect.left], [Rect.top], [Rect.right], [Rect.bottom]).\n        //\n        // The `colors` argument, which can be null, is interpreted as a list of\n        // 32-bit colors, with the same packing as [Color.value].\n        //\n        // See also:\n        //\n        //  * [drawAtlas], which takes its arguments as objects rather than typed\n        //    data lists.\n        public void DrawRawAtlas(SKImage atlas,\n                          List<double> rstTransforms,\n                          List<double> rects,\n                          List<uint> colors,\n                          BlendMode blendMode,\n                          Rect cullRect,\n                          SKPaint paint)\n        {\n            ////assert(atlas != null); // atlas is checked on the engine side\n            ////assert(rstTransforms != null);\n            ////assert(rects != null);\n            ////assert(colors != null);\n            ////assert(blendMode != null);\n            ////assert(paint != null);\n\n            int rectCount = rects.Count;\n            if (rstTransforms.Count != rectCount)\n                throw new ArgumentException(\"'rstTransforms' and 'rects' lengths must match.\");\n            if (rectCount % 4 != 0)\n                throw new ArgumentException(\"'rstTransforms' and 'rects' lengths must be a multiple of four.\");\n            if (colors != null && colors.Count * 4 != rectCount)\n                throw new ArgumentException(\"If non-null, 'colors' length must be one fourth the length of 'rstTransforms' and 'rects'.\");\n\n            //TODO SKPaint and Paint is mixed up here\n            /* _drawAtlas(\n              paint._objects, paint._data, atlas, rstTransforms, rects,\n              colors, (int)blendMode, cullRect?._value\n            ); */\n        }\n\n        void _drawAtlas(List<Object> paintObjects,\n                        ByteData paintData,\n                        SKImage atlas,\n                        List<double> rstTransforms,\n                        List<double> rects,\n                        List<uint> colors,\n                        int blendMode,\n                        List<double> cullRect)\n        {\n            // native 'Canvas_drawAtlas';\n        }\n\n        /// Draws a shadow for a [Path] representing the given material elevation.\n        ///\n        /// The `transparentOccluder` argument should be true if the occluding object\n        /// is not opaque.\n        ///\n        /// The arguments must not be null.\n        public void DrawShadow(Path path, Color color, double elevation, bool transparentOccluder)\n        {\n            //assert(path != null); // path is checked on the engine side\n            //assert(color != null);\n            //assert(transparentOccluder != null);\n\n            // TODO: Draw shadow\n            // https://github.com/flutter/engine/blob/master/lib/ui/painting/canvas.cc\n            // Requires: Flow.PhysicalShapeLayer\n            \n        }       \n    }\n\n    /// Records a [Picture] containing a sequence of graphical operations.\n    ///\n    /// To begin recording, construct a [Canvas] to record the commands.\n    /// To end recording, use the [PictureRecorder.endRecording] method.\n    public class PictureRecorder : NativePictureRecorder\n    {\n        /// Whether this object is currently recording commands.\n        ///\n        /// Specifically, this returns true if a [Canvas] object has been\n        /// created to record commands and recording has not yet ended via a\n        /// call to [endRecording], and false if either this\n        /// [PictureRecorder] has not yet been associated with a [Canvas],\n        /// or the [endRecording] method has already been called.\n        public bool isRecording\n        {\n            get\n            {\n                return this.RecordingCanvas != null;\n            }\n        }\n        /// Finishes recording graphical operations.\n        ///\n        /// Returns a picture containing the graphical operations that have been\n        /// recorded thus far. After calling this function, both the picture recorder\n        /// and the canvas objects are invalid and cannot be used further.\n        ///\n        /// Returns null if the PictureRecorder is not associated with a canvas.\n        public SKPicture endRecording()\n        {\n            return this.EndRecording();\n        }\n    }\n\n    /// A single shadow.\n    ///\n    /// Multiple shadows are stacked together in a [TextStyle].\n    public class Shadow\n    {\n        /// Construct a shadow.\n        ///\n        /// The default shadow is a black shadow with zero offset and zero blur.\n        /// Default shadows should be completely covered by the casting element,\n        /// and not be visble.\n        ///\n        /// Transparency should be adjusted through the [color] alpha.\n        ///\n        /// Shadow order matters due to compositing multiple translucent objects not\n        /// being commutative.\n        public Shadow(Color color = null,\n                      Offset offset = null,\n                      double blurRadius = 0.0)\n        {\n            //assert(color != null, 'Text shadow color was null.'),\n            //assert(offset != null, 'Text shadow offset was null.'),\n            //assert(blurRadius >= 0.0, 'Text shadow blur radius should be non-negative.');\n            if (color == null)\n                this.color = new Color(_kColorDefault);\n            else\n                this.color = color;\n\n            if (offset == null)\n                this.offset = Offset.zero;\n            else\n                this.offset = offset;\n\n            this.blurRadius = blurRadius;\n        }\n\n        const uint _kColorDefault = 0xFF000000;\n        // Constants for shadow encoding.\n        const int _kBytesPerShadow = 16;\n        const int _kColorOffset = 0 << 2;\n        const int _kXOffset = 1 << 2;\n        const int _kYOffset = 2 << 2;\n        const int _kBlurOffset = 3 << 2;\n\n        /// Color that the shadow will be drawn with.\n        ///\n        /// The shadows are shapes composited directly over the base canvas, and do not\n        /// represent optical occlusion.\n        public readonly Color color;\n\n        /// The displacement of the shadow from the casting element.\n        ///\n        /// Positive x/y offsets will shift the shadow to the right and down, while\n        /// negative offsets shift the shadow to the left and up. The offsets are\n        /// relative to the position of the element that is casting it.\n        public readonly Offset offset;\n\n        /// The standard deviation of the Gaussian to convolve with the shadow's shape.\n        public readonly double blurRadius;\n\n        /// Converts a blur radius in pixels to sigmas.\n        ///\n        /// See the sigma argument to [MaskFilter.blur].\n        ///\n        // See SkBlurMask::ConvertRadiusToSigma().\n        // <https://github.com/google/skia/blob/bb5b77db51d2e149ee66db284903572a5aac09be/src/effects/SkBlurMask.cpp#L23>\n        static double convertRadiusToSigma(double radius)\n        {\n            return radius * 0.57735 + 0.5;\n        }\n\n        /// The [blurRadius] in sigmas instead of logical pixels.\n        ///\n        /// See the sigma argument to [MaskFilter.blur].\n        public double blurSigma => convertRadiusToSigma(blurRadius);\n\n        /// Create the [Paint] object that corresponds to this shadow description.\n        ///\n        /// The [offset] is not represented in the [Paint] object.\n        /// To honor this as well, the shape should be translated by [offset] before\n        /// being filled using this [Paint].\n        ///\n        /// This class does not provide a way to disable shadows to avoid inconsistencies\n        /// in shadow blur rendering, primarily as a method of reducing test flakiness.\n        /// [toPaint] should be overriden in subclasses to provide this functionality.\n        public Paint toPaint()\n        {\n            return new Paint\n            {\n                color = color,\n                maskFilter = MaskFilter.blur(BlurStyle.normal, blurSigma)\n            };\n        }\n\n        /// Returns a new shadow with its [offset] and [blurRadius] scaled by the given\n        /// factor.\n        public Shadow scale(double factor)\n        {\n            return new Shadow(\n              color: color,\n              offset: offset * factor,\n              blurRadius: blurRadius * factor);\n        }\n\n        /// Linearly interpolate between two shadows.\n        ///\n        /// If either shadow is null, this function linearly interpolates from a\n        /// a shadow that matches the other shadow in color but has a zero\n        /// offset and a zero blurRadius.\n        ///\n        /// {@template dart.ui.shadow.lerp}\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]).\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        /// {@endtemplate}\n        public static Shadow lerp(Shadow a, Shadow b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n            if (a == null)\n                return b.scale(t);\n            if (b == null)\n                return a.scale(1.0 - t);\n            return new Shadow(\n              color: Color.lerp(a.color, b.color, t),\n              offset: Offset.lerp(a.offset, b.offset, t),\n              blurRadius: lerpDouble(a.blurRadius, b.blurRadius, t));\n        }\n\n        /// Linearly interpolate between two lists of shadows.\n        ///\n        /// If the lists differ in length, excess items are lerped with null.\n        ///\n        /// {@macro dart.ui.shadow.lerp}\n        static List<Shadow> lerpList(List<Shadow> a, List<Shadow> b, double t)\n        {\n            //assert(t != null);\n            if (a == null && b == null)\n                return null;\n\n            if (a == null)\n                a = new List<Shadow>();\n\n            if (b == null)\n                b = new List<Shadow>();\n\n            List<Shadow> result = new List<Shadow>();\n            int commonLength = Math.Min(a.Count, b.Count);\n            for (int i = 0; i < commonLength; i += 1)\n                result.Add(Shadow.lerp(a[i], b[i], t));\n            for (int i = commonLength; i < a.Count; i += 1)\n                result.Add(a[i].scale(1.0 - t));\n            for (int i = commonLength; i < b.Count; i += 1)\n                result.Add(b[i].scale(t));\n            return result;\n        }\n\n        public static bool operator ==(Shadow first, Shadow second)\n        {\n            if (identical(first, second))\n                return true;\n\n            Shadow typedOther = second;\n            return first.color == typedOther.color &&\n                   first.offset == typedOther.offset &&\n                   first.blurRadius == typedOther.blurRadius;\n        }\n\n        public static bool operator !=(Shadow first, Shadow second) => !(first == second);\n\n        public int hashCode => hashValues(color, offset, blurRadius);\n\n        /// Determines if lists [a] and [b] are deep equivalent.\n        ///\n        /// Returns true if the lists are both null, or if they are both non-null, have\n        /// the same length, and contain the same Shadows in the same order. Returns\n        /// false otherwise.\n        public static bool _shadowsListEquals(List<Shadow> a, List<Shadow> b)\n        {\n            // Compare _shadows\n            if (a == null)\n                return b == null;\n            if (b == null || a.Count != b.Count)\n                return false;\n            for (int index = 0; index < a.Count; ++index)\n                if (a[index] != b[index])\n                    return false;\n            return true;\n        }\n\n        // Serialize [shadows] into ByteData. The format is a single uint_32_t at\n        // the beginning indicating the number of shadows, followed by _kBytesPerShadow\n        // bytes for each shadow.\n        public static ByteData _encodeShadows(List<Shadow> shadows)\n        {\n            if (shadows == null)\n                return new ByteData(0);\n\n            int byteCount = shadows.Count * _kBytesPerShadow;\n            ByteData shadowsData = new ByteData(byteCount);\n\n            int shadowOffset = 0;\n            for (int shadowIndex = 0; shadowIndex < shadows.Count; ++shadowIndex)\n            {\n                Shadow shadow = shadows[shadowIndex];\n                if (shadow == null)\n                    continue;\n                shadowOffset = shadowIndex * _kBytesPerShadow;\n\n                shadowsData.setInt32(_kColorOffset + shadowOffset,\n                 (int)(shadow.color.value ^ Shadow._kColorDefault), (int)_kFakeHostEndian);\n\n                shadowsData.setFloat32(_kXOffset + shadowOffset,\n                  shadow.offset.dx, (int)_kFakeHostEndian);\n\n                shadowsData.setFloat32(_kYOffset + shadowOffset,\n                  shadow.offset.dy, (int)_kFakeHostEndian);\n\n                shadowsData.setFloat32(_kBlurOffset + shadowOffset,\n                  shadow.blurRadius, (int)_kFakeHostEndian);\n            }\n\n            return shadowsData;\n        }\n\n        public String toString() => $\"TextShadow({color}, {offset}, {blurRadius})\";\n    }\n\n    // TODO: I think these should just be Action's or Func's no need for a delegate\n    /// Generic callback signature, used by [_futurize].\n    public delegate void _Callback<T>(T result);\n    public delegate void _Callback();\n\n    /// Signature for a method that receives a [_Callback].\n    ///\n    /// Return value should be null on success, and a string error message on\n    /// failure.\n    public delegate String _Callbacker<T>(_Callback<T> callback);\n}"
  },
  {
    "path": "FlutterBinding/UI/Pointer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing static FlutterBinding.Mapping.Types;\n\nnamespace FlutterBinding.UI\n{\n\n    /// How the pointer has changed since the last report.\n    public enum PointerChange\n    {\n        /// The input from the pointer is no longer directed towards this receiver.\n        cancel,\n\n        /// The device has started tracking the pointer.\n        ///\n        /// For example, the pointer might be hovering above the device, having not yet\n        /// made contact with the surface of the device.\n        add,\n\n        /// The device is no longer tracking the pointer.\n        ///\n        /// For example, the pointer might have drifted out of the device's hover\n        /// detection range or might have been disconnected from the system entirely.\n        remove,\n\n        /// The pointer has moved with respect to the device while not in contact with\n        /// the device.\n        hover,\n\n        /// The pointer has made contact with the device.\n        down,\n\n        /// The pointer has moved with respect to the device while in contact with the\n        /// device.\n        move,\n\n        /// The pointer has stopped making contact with the device.\n        up,\n    }\n\n    /// The kind of pointer device.\n    public enum PointerDeviceKind\n    {\n        /// A touch-based pointer device.\n        touch,\n\n        /// A mouse-based pointer device.\n        mouse,\n\n        /// A pointer device with a stylus.\n        stylus,\n\n        /// A pointer device with a stylus that has been inverted.\n        invertedStylus,\n\n        /// An unknown pointer device.\n        unknown\n    }\n\n    /// Information about the state of a pointer.\n    public class PointerData\n    {\n        /// Creates an object that represents the state of a pointer.\n        public PointerData(\n          Duration timeStamp = null,\n          PointerChange change = PointerChange.cancel,\n          PointerDeviceKind kind = PointerDeviceKind.touch,\n          int device = 0,\n          double physicalX = 0.0,\n          double physicalY = 0.0,\n          int buttons = 0,\n          bool obscured = false,\n          double pressure = 0.0,\n          double pressureMin = 0.0,\n          double pressureMax = 0.0,\n          double distance = 0.0,\n          double distanceMax = 0.0,\n          double radiusMajor = 0.0,\n          double radiusMinor = 0.0,\n          double radiusMin = 0.0,\n          double radiusMax = 0.0,\n          double orientation = 0.0,\n          double tilt = 0.0\n      )\n        {\n            if (timeStamp == null)\n                timeStamp = Duration.zero;\n\n            this.timeStamp = timeStamp;\n            this.change = change;\n            this.kind = kind;\n            this.device = device;\n            this.physicalX = physicalX;\n            this.physicalY = physicalY;\n            this.buttons = buttons;\n            this.obscured = obscured;\n            this.pressure = pressure;\n            this.pressureMin = pressureMin;\n            this.pressureMax = pressureMax;\n            this.distance = distance;\n            this.distanceMax = distanceMax;\n            this.radiusMajor = radiusMajor;\n            this.radiusMinor = radiusMinor;\n            this.radiusMin = radiusMin;\n            this.radiusMax = radiusMax;\n            this.orientation = orientation;\n            this.tilt = tilt;\n        }\n\n        /// Time of event dispatch, relative to an arbitrary timeline.\n        public readonly Duration timeStamp;\n\n        /// How the pointer has changed since the last report.\n        public readonly PointerChange change;\n\n        /// The kind of input device for which the event was generated.\n        public readonly PointerDeviceKind kind;\n\n        /// Unique identifier for the pointing device, reused across interactions.\n        public readonly int device;\n\n        /// X coordinate of the position of the pointer, in physical pixels in the\n        /// global coordinate space.\n        public readonly double physicalX;\n\n        /// Y coordinate of the position of the pointer, in physical pixels in the\n        /// global coordinate space.\n        public readonly double physicalY;\n\n        /// Bit field using the *Button constants (primaryMouseButton,\n        /// secondaryStylusButton, etc). For example, if this has the value 6 and the\n        /// [kind] is [PointerDeviceKind.invertedStylus], then this indicates an\n        /// upside-down stylus with both its primary and secondary buttons pressed.\n        public readonly int buttons;\n\n        /// Set if an application from a different security domain is in any way\n        /// obscuring this application's window. (Aspirational; not currently\n        /// implemented.)\n        public readonly bool obscured;\n\n        /// The pressure of the touch as a number ranging from 0.0, indicating a touch\n        /// with no discernible pressure, to 1.0, indicating a touch with \"normal\"\n        /// pressure, and possibly beyond, indicating a stronger touch. For devices\n        /// that do not detect pressure (e.g. mice), returns 1.0.\n        public readonly double pressure;\n\n        /// The minimum value that [pressure] can return for this pointer. For devices\n        /// that do not detect pressure (e.g. mice), returns 1.0. This will always be\n        /// a number less than or equal to 1.0.\n        public readonly double pressureMin;\n\n        /// The maximum value that [pressure] can return for this pointer. For devices\n        /// that do not detect pressure (e.g. mice), returns 1.0. This will always be\n        /// a greater than or equal to 1.0.\n        public readonly double pressureMax;\n\n        /// The distance of the detected object from the input surface (e.g. the\n        /// distance of a stylus or finger from a touch screen), in arbitrary units on\n        /// an arbitrary (not necessarily linear) scale. If the pointer is down, this\n        /// is 0.0 by definition.\n        public readonly double distance;\n\n        /// The maximum value that a distance can return for this pointer. If this\n        /// input device cannot detect \"hover touch\" input events, then this will be\n        /// 0.0.\n        public readonly double distanceMax;\n\n        /// The radius of the contact ellipse along the major axis, in logical pixels.\n        public readonly double radiusMajor;\n\n        /// The radius of the contact ellipse along the minor axis, in logical pixels.\n        public readonly double radiusMinor;\n\n        /// The minimum value that could be reported for radiusMajor and radiusMinor\n        /// for this pointer, in logical pixels.\n        public readonly double radiusMin;\n\n        /// The minimum value that could be reported for radiusMajor and radiusMinor\n        /// for this pointer, in logical pixels.\n        public readonly double radiusMax;\n\n        /// For PointerDeviceKind.touch events:\n        ///\n        /// The angle of the contact ellipse, in radius in the range:\n        ///\n        ///    -pi/2 < orientation <= pi/2\n        ///\n        /// ...giving the angle of the major axis of the ellipse with the y-axis\n        /// (negative angles indicating an orientation along the top-left /\n        /// bottom-right diagonal, positive angles indicating an orientation along the\n        /// top-right / bottom-left diagonal, and zero indicating an orientation\n        /// parallel with the y-axis).\n        ///\n        /// For PointerDeviceKind.stylus and PointerDeviceKind.invertedStylus events:\n        ///\n        /// The angle of the stylus, in radians in the range:\n        ///\n        ///    -pi < orientation <= pi\n        ///\n        /// ...giving the angle of the axis of the stylus projected onto the input\n        /// surface, relative to the positive y-axis of that surface (thus 0.0\n        /// indicates the stylus, if projected onto that surface, would go from the\n        /// contact point vertically up in the positive y-axis direction, pi would\n        /// indicate that the stylus would go down in the negative y-axis direction;\n        /// pi/4 would indicate that the stylus goes up and to the right, -pi/2 would\n        /// indicate that the stylus goes to the left, etc).\n        public readonly double orientation;\n\n        /// For PointerDeviceKind.stylus and PointerDeviceKind.invertedStylus events:\n        ///\n        /// The angle of the stylus, in radians in the range:\n        ///\n        ///    0 <= tilt <= pi/2\n        ///\n        /// ...giving the angle of the axis of the stylus, relative to the axis\n        /// perpendicular to the input surface (thus 0.0 indicates the stylus is\n        /// orthogonal to the plane of the input surface, while pi/2 indicates that\n        /// the stylus is flat on that surface).\n        public readonly double tilt;\n\n        public String toString() => $\"{nameof(PointerData)}(x: {physicalX}, y: {physicalY})\";\n\n        /// Returns a complete textual description of the information in this object.\n        public String toStringFull()\n        {\n            return $\"{nameof(PointerData)}(\" +\n                   $\"timeStamp: {timeStamp}, \" +\n                   $\"change: {change}, \" +\n                   $\"kind: {kind}, \" +\n                   $\"device: {device}, \" +\n                   $\"physicalX: {physicalX}, \" +\n                   $\"physicalY: {physicalY}, \" +\n                   $\"buttons: {buttons}, \" +\n                   $\"pressure: {pressure}, \" +\n                   $\"pressureMin: {pressureMin}, \" +\n                   $\"pressureMax: {pressureMax}, \" +\n                   $\"distance: {distance}, \" +\n                   $\"distanceMax: {distanceMax}, \" +\n                   $\"radiusMajor: {radiusMajor}, \" +\n                   $\"radiusMinor: {radiusMinor}, \" +\n                   $\"radiusMin: {radiusMin}, \" +\n                   $\"radiusMax: {radiusMax}, \" +\n                   $\"orientation: {orientation}, \" +\n                   $\"tilt: {tilt}\" +\n                    \")\";\n        }\n    }\n\n    /// A sequence of reports about the state of pointers.\n    public class PointerDataPacket\n    {\n        /// Creates a packet of pointer data reports.\n        public PointerDataPacket(List<PointerData> data = null)\n        {\n            if (data == null)\n                data = new List<PointerData>();\n\n            this.data = data;\n        }\n\n        /// Data about the individual pointers in this packet.\n        ///\n        /// This list might contain multiple pieces of data about the same pointer.\n        public readonly List<PointerData> data;\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Semantics.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace FlutterBinding.UI\n{\n\n    /// The possible actions that can be conveyed from the operating system\n    /// accessibility APIs to a semantics node.\n    public class SemanticsAction\n    {\n        private SemanticsAction(int index)\n        {\n            this.index = index;\n        }\n\n        const int _kTapIndex = 1 << 0;\n        const int _kLongPressIndex = 1 << 1;\n        const int _kScrollLeftIndex = 1 << 2;\n        const int _kScrollRightIndex = 1 << 3;\n        const int _kScrollUpIndex = 1 << 4;\n        const int _kScrollDownIndex = 1 << 5;\n        const int _kIncreaseIndex = 1 << 6;\n        const int _kDecreaseIndex = 1 << 7;\n        const int _kShowOnScreenIndex = 1 << 8;\n        const int _kMoveCursorForwardByCharacterIndex = 1 << 9;\n        const int _kMoveCursorBackwardByCharacterIndex = 1 << 10;\n        const int _kSetSelectionIndex = 1 << 11;\n        const int _kCopyIndex = 1 << 12;\n        const int _kCutIndex = 1 << 13;\n        const int _kPasteIndex = 1 << 14;\n        const int _kDidGainAccessibilityFocusIndex = 1 << 15;\n        const int _kDidLoseAccessibilityFocusIndex = 1 << 16;\n        const int _kCustomAction = 1 << 17;\n        const int _kDismissIndex = 1 << 18;\n        const int _kMoveCursorForwardByWordIndex = 1 << 19;\n        const int _kMoveCursorBackwardByWordIndex = 1 << 20;\n\n        /// The numerical value for this action.\n        ///\n        /// Each action has one bit set in this bit field.\n        public readonly int index;\n\n        /// The equivalent of a user briefly tapping the screen with the finger\n        /// without moving it.\n        public static SemanticsAction tap = new SemanticsAction(_kTapIndex);\n\n        /// The equivalent of a user pressing and holding the screen with the finger\n        /// for a few seconds without moving it.\n        public static SemanticsAction longPress = new SemanticsAction(_kLongPressIndex);\n\n        /// The equivalent of a user moving their finger across the screen from right\n        /// to left.\n        ///\n        /// This action should be recognized by controls that are horizontally\n        /// scrollable.\n        public static SemanticsAction scrollLeft = new SemanticsAction(_kScrollLeftIndex);\n\n        /// The equivalent of a user moving their finger across the screen from left\n        /// to right.\n        ///\n        /// This action should be recognized by controls that are horizontally\n        /// scrollable.\n        public static SemanticsAction scrollRight = new SemanticsAction(_kScrollRightIndex);\n\n        /// The equivalent of a user moving their finger across the screen from\n        /// bottom to top.\n        ///\n        /// This action should be recognized by controls that are vertically\n        /// scrollable.\n        public static SemanticsAction scrollUp = new SemanticsAction(_kScrollUpIndex);\n\n        /// The equivalent of a user moving their finger across the screen from top\n        /// to bottom.\n        ///\n        /// This action should be recognized by controls that are vertically\n        /// scrollable.\n        public static SemanticsAction scrollDown = new SemanticsAction(_kScrollDownIndex);\n\n        /// A request to increase the value represented by the semantics node.\n        ///\n        /// For example, this action might be recognized by a slider control.\n        public static SemanticsAction increase = new SemanticsAction(_kIncreaseIndex);\n\n        /// A request to decrease the value represented by the semantics node.\n        ///\n        /// For example, this action might be recognized by a slider control.\n        public static SemanticsAction decrease = new SemanticsAction(_kDecreaseIndex);\n\n        /// A request to fully show the semantics node on screen.\n        ///\n        /// For example, this action might be send to a node in a scrollable list that\n        /// is partially off screen to bring it on screen.\n        public static SemanticsAction showOnScreen = new SemanticsAction(_kShowOnScreenIndex);\n\n        /// Move the cursor forward by one character.\n        ///\n        /// This is for example used by the cursor control in text fields.\n        ///\n        /// The action includes a boolean argument, which indicates whether the cursor\n        /// movement should extend (or start) a selection.\n        public static SemanticsAction moveCursorForwardByCharacter = new SemanticsAction(_kMoveCursorForwardByCharacterIndex);\n\n        /// Move the cursor backward by one character.\n        ///\n        /// This is for example used by the cursor control in text fields.\n        ///\n        /// The action includes a boolean argument, which indicates whether the cursor\n        /// movement should extend (or start) a selection.\n        public static SemanticsAction moveCursorBackwardByCharacter = new SemanticsAction(_kMoveCursorBackwardByCharacterIndex);\n\n        /// Set the text selection to the given range.\n        ///\n        /// The provided argument is a Map<String, int> which includes the keys `base`\n        /// and `extent` indicating where the selection within the `value` of the\n        /// semantics node should start and where it should end. Values for both\n        /// keys can range from 0 to length of `value` (inclusive).\n        ///\n        /// Setting `base` and `extent` to the same value will move the cursor to\n        /// that position (without selecting anything).\n        public static SemanticsAction setSelection = new SemanticsAction(_kSetSelectionIndex);\n\n        /// Copy the current selection to the clipboard.\n        public static SemanticsAction copy = new SemanticsAction(_kCopyIndex);\n\n        /// Cut the current selection and place it in the clipboard.\n        public static SemanticsAction cut = new SemanticsAction(_kCutIndex);\n\n        /// Paste the current content of the clipboard.\n        public static SemanticsAction paste = new SemanticsAction(_kPasteIndex);\n\n        /// Indicates that the nodes has gained accessibility focus.\n        ///\n        /// This handler is invoked when the node annotated with this handler gains\n        /// the accessibility focus. The accessibility focus is the\n        /// green (on Android with TalkBack) or black (on iOS with VoiceOver)\n        /// rectangle shown on screen to indicate what element an accessibility\n        /// user is currently interacting with.\n        ///\n        /// The accessibility focus is different from the input focus. The input focus\n        /// is usually held by the element that currently responds to keyboard inputs.\n        /// Accessibility focus and input focus can be held by two different nodes!\n        public static SemanticsAction didGainAccessibilityFocus = new SemanticsAction(_kDidGainAccessibilityFocusIndex);\n\n        /// Indicates that the nodes has lost accessibility focus.\n        ///\n        /// This handler is invoked when the node annotated with this handler\n        /// loses the accessibility focus. The accessibility focus is\n        /// the green (on Android with TalkBack) or black (on iOS with VoiceOver)\n        /// rectangle shown on screen to indicate what element an accessibility\n        /// user is currently interacting with.\n        ///\n        /// The accessibility focus is different from the input focus. The input focus\n        /// is usually held by the element that currently responds to keyboard inputs.\n        /// Accessibility focus and input focus can be held by two different nodes!\n        public static SemanticsAction didLoseAccessibilityFocus = new SemanticsAction(_kDidLoseAccessibilityFocusIndex);\n\n        /// Indicates that the user has invoked a custom accessibility action.\n        ///\n        /// This handler is added automatically whenever a custom accessibility\n        /// action is added to a semantics node.\n        public static SemanticsAction customAction = new SemanticsAction(_kCustomAction);\n\n        /// A request that the node should be dismissed.\n        ///\n        /// A [Snackbar], for example, may have a dismiss action to indicate to the\n        /// user that it can be removed after it is no longer relevant. On Android,\n        /// (with TalkBack) special hint text is spoken when focusing the node and\n        /// a custom action is availible in the local context menu. On iOS,\n        /// (with VoiceOver) users can perform a standard gesture to dismiss it.\n        public static SemanticsAction dismiss = new SemanticsAction(_kDismissIndex);\n\n        /// Move the cursor forward by one word.\n        ///\n        /// This is for example used by the cursor control in text fields.\n        ///\n        /// The action includes a boolean argument, which indicates whether the cursor\n        /// movement should extend (or start) a selection.\n        public static SemanticsAction moveCursorForwardByWord = new SemanticsAction(_kMoveCursorForwardByWordIndex);\n\n        /// Move the cursor backward by one word.\n        ///\n        /// This is for example used by the cursor control in text fields.\n        ///\n        /// The action includes a boolean argument, which indicates whether the cursor\n        /// movement should extend (or start) a selection.\n        public static SemanticsAction moveCursorBackwardByWord = new SemanticsAction(_kMoveCursorBackwardByWordIndex);\n\n        /// The possible semantics actions.\n        ///\n        /// The map's key is the [index] of the action and the value is the action\n        /// itself.\n        public static Dictionary<int, SemanticsAction> values = new Dictionary<int, SemanticsAction>{\n            { _kTapIndex, tap },\n             { _kLongPressIndex, longPress },\n             { _kScrollLeftIndex, scrollLeft },\n             { _kScrollRightIndex, scrollRight },\n             { _kScrollUpIndex, scrollUp },\n             { _kScrollDownIndex, scrollDown },\n             { _kIncreaseIndex, increase },\n             { _kDecreaseIndex, decrease },\n             { _kShowOnScreenIndex, showOnScreen },\n             { _kMoveCursorForwardByCharacterIndex, moveCursorForwardByCharacter },\n             { _kMoveCursorBackwardByCharacterIndex, moveCursorBackwardByCharacter },\n            {  _kSetSelectionIndex, setSelection },\n             { _kCopyIndex, copy },\n             { _kCutIndex, cut },\n            {  _kPasteIndex, paste },\n            {  _kDidGainAccessibilityFocusIndex, didGainAccessibilityFocus },\n            {  _kDidLoseAccessibilityFocusIndex, didLoseAccessibilityFocus },\n            {  _kCustomAction, customAction },\n            {  _kDismissIndex, dismiss },\n            {  _kMoveCursorForwardByWordIndex, moveCursorForwardByWord },\n            {  _kMoveCursorBackwardByWordIndex, moveCursorBackwardByWord }  };\n\n        public String toString()\n        {\n            switch (index)\n            {\n                case _kTapIndex:\n                    return \"SemanticsAction.tap\";\n                case _kLongPressIndex:\n                    return \"SemanticsAction.longPress\";\n                case _kScrollLeftIndex:\n                    return \"SemanticsAction.scrollLeft\";\n                case _kScrollRightIndex:\n                    return \"SemanticsAction.scrollRight\";\n                case _kScrollUpIndex:\n                    return \"SemanticsAction.scrollUp\";\n                case _kScrollDownIndex:\n                    return \"SemanticsAction.scrollDown\";\n                case _kIncreaseIndex:\n                    return \"SemanticsAction.increase\";\n                case _kDecreaseIndex:\n                    return \"SemanticsAction.decrease\";\n                case _kShowOnScreenIndex:\n                    return \"SemanticsAction.showOnScreen\";\n                case _kMoveCursorForwardByCharacterIndex:\n                    return \"SemanticsAction.moveCursorForwardByCharacter\";\n                case _kMoveCursorBackwardByCharacterIndex:\n                    return \"SemanticsAction.moveCursorBackwardByCharacter\";\n                case _kSetSelectionIndex:\n                    return \"SemanticsAction.setSelection\";\n                case _kCopyIndex:\n                    return \"SemanticsAction.copy\";\n                case _kCutIndex:\n                    return \"SemanticsAction.cut\";\n                case _kPasteIndex:\n                    return \"SemanticsAction.paste\";\n                case _kDidGainAccessibilityFocusIndex:\n                    return \"SemanticsAction.didGainAccessibilityFocus\";\n                case _kDidLoseAccessibilityFocusIndex:\n                    return \"SemanticsAction.didLoseAccessibilityFocus\";\n                case _kCustomAction:\n                    return \"SemanticsAction.customAction\";\n                case _kDismissIndex:\n                    return \"SemanticsAction.dismiss\";\n                case _kMoveCursorForwardByWordIndex:\n                    return \"SemanticsAction.moveCursorForwardByWord\";\n                case _kMoveCursorBackwardByWordIndex:\n                    return \"SemanticsAction.moveCursorBackwardByWord\";\n            }\n            return null;\n        }\n    }\n\n    /// A Boolean value that can be associated with a semantics node.\n    public class SemanticsFlag\n    {\n        const int _kHasCheckedStateIndex = 1 << 0;\n        const int _kIsCheckedIndex = 1 << 1;\n        const int _kIsSelectedIndex = 1 << 2;\n        const int _kIsButtonIndex = 1 << 3;\n        const int _kIsTextFieldIndex = 1 << 4;\n        const int _kIsFocusedIndex = 1 << 5;\n        const int _kHasEnabledStateIndex = 1 << 6;\n        const int _kIsEnabledIndex = 1 << 7;\n        const int _kIsInMutuallyExclusiveGroupIndex = 1 << 8;\n        const int _kIsHeaderIndex = 1 << 9;\n        const int _kIsObscuredIndex = 1 << 10;\n        const int _kScopesRouteIndex = 1 << 11;\n        const int _kNamesRouteIndex = 1 << 12;\n        const int _kIsHiddenIndex = 1 << 13;\n        const int _kIsImageIndex = 1 << 14;\n        const int _kIsLiveRegionIndex = 1 << 15;\n        const int _kHasToggledStateIndex = 1 << 16;\n        const int _kIsToggledIndex = 1 << 17;\n        const int _kHasImplicitScrollingIndex = 1 << 18;\n\n        public SemanticsFlag(int index)\n        {\n            this.index = index;\n        }\n\n        /// The numerical value for this flag.\n        ///\n        /// Each flag has one bit set in this bit field.\n        public readonly int index;\n\n        /// The semantics node has the quality of either being \"checked\" or \"unchecked\".\n        ///\n        /// This flag is mutually exclusive with [hasToggledState].\n        ///\n        /// For example, a checkbox or a radio button widget has checked state.\n        ///\n        /// See also:\n        ///\n        ///   * [SemanticsFlag.isChecked], which controls whether the node is \"checked\" or \"unchecked\".\n        public static SemanticsFlag hasCheckedState = new SemanticsFlag(_kHasCheckedStateIndex);\n\n        /// Whether a semantics node that [hasCheckedState] is checked.\n        ///\n        /// If true, the semantics node is \"checked\". If false, the semantics node is\n        /// \"unchecked\".\n        ///\n        /// For example, if a checkbox has a visible checkmark, [isChecked] is true.\n        ///\n        /// See also:\n        ///\n        ///   * [SemanticsFlag.hasCheckedState], which enables a checked state.\n        public static SemanticsFlag isChecked = new SemanticsFlag(_kIsCheckedIndex);\n\n\n        /// Whether a semantics node is selected.\n        ///\n        /// If true, the semantics node is \"selected\". If false, the semantics node is\n        /// \"unselected\".\n        ///\n        /// For example, the active tab in a tab bar has [isSelected] set to true.\n        public static SemanticsFlag isSelected = new SemanticsFlag(_kIsSelectedIndex);\n\n        /// Whether the semantic node represents a button.\n        ///\n        /// Platforms has special handling for buttons, for example Android's TalkBack\n        /// and iOS's VoiceOver provides an additional hint when the focused object is\n        /// a button.\n        public static SemanticsFlag isButton = new SemanticsFlag(_kIsButtonIndex);\n\n        /// Whether the semantic node represents a text field.\n        ///\n        /// Text fields are announced as such and allow text input via accessibility\n        /// affordances.\n        public static SemanticsFlag isTextField = new SemanticsFlag(_kIsTextFieldIndex);\n\n        /// Whether the semantic node currently holds the user's focus.\n        ///\n        /// The focused element is usually the current receiver of keyboard inputs.\n        public static SemanticsFlag isFocused = new SemanticsFlag(_kIsFocusedIndex);\n\n        /// The semantics node has the quality of either being \"enabled\" or\n        /// \"disabled\".\n        ///\n        /// For example, a button can be enabled or disabled and therefore has an\n        /// \"enabled\" state. Static text is usually neither enabled nor disabled and\n        /// therefore does not have an \"enabled\" state.\n        public static SemanticsFlag hasEnabledState = new SemanticsFlag(_kHasEnabledStateIndex);\n\n        /// Whether a semantic node that [hasEnabledState] is currently enabled.\n        ///\n        /// A disabled element does not respond to user interaction. For example, a\n        /// button that currently does not respond to user interaction should be\n        /// marked as disabled.\n        public static SemanticsFlag isEnabled = new SemanticsFlag(_kIsEnabledIndex);\n\n        /// Whether a semantic node is in a mutually exclusive group.\n        ///\n        /// For example, a radio button is in a mutually exclusive group because\n        /// only one radio button in that group can be marked as [isChecked].\n        public static SemanticsFlag isInMutuallyExclusiveGroup = new SemanticsFlag(_kIsInMutuallyExclusiveGroupIndex);\n\n        /// Whether a semantic node is a header that divides content into sections.\n        ///\n        /// For example, headers can be used to divide a list of alphabetically\n        /// sorted words into the sections A, B, C, etc. as can be found in many\n        /// address book applications.\n        public static SemanticsFlag isHeader = new SemanticsFlag(_kIsHeaderIndex);\n\n        /// Whether the value of the semantics node is obscured.\n        ///\n        /// This is usually used for text fields to indicate that its content\n        /// is a password or contains other sensitive information.\n        public static SemanticsFlag isObscured = new SemanticsFlag(_kIsObscuredIndex);\n\n        /// Whether the semantics node is the root of a subtree for which a route name\n        /// should be announced.\n        ///\n        /// When a node with this flag is removed from the semantics tree, the\n        /// framework will select the last in depth-first, paint order node with this\n        /// flag.  When a node with this flag is added to the semantics tree, it is\n        /// selected automatically, unless there were multiple nodes with this flag\n        /// added.  In this case, the last added node in depth-first, paint order\n        /// will be selected.\n        ///\n        /// From this selected node, the framework will search in depth-first, paint\n        /// order for the first node with a [namesRoute] flag and a non-null,\n        /// non-empty label. The [namesRoute] and [scopesRoute] flags may be on the\n        /// same node. The label of the found node will be announced as an edge\n        /// transition. If no non-empty, non-null label is found then:\n        ///\n        ///   * VoiceOver will make a chime announcement.\n        ///   * TalkBack will make no announcement\n        ///\n        /// Semantic nodes annotated with this flag are generally not a11y focusable.\n        ///\n        /// This is used in widgets such as Routes, Drawers, and Dialogs to\n        /// communicate significant changes in the visible screen.\n        public static SemanticsFlag scopesRoute = new SemanticsFlag(_kScopesRouteIndex);\n\n        /// Whether the semantics node label is the name of a visually distinct\n        /// route.\n        ///\n        /// This is used by certain widgets like Drawers and Dialogs, to indicate\n        /// that the node's semantic label can be used to announce an edge triggered\n        /// semantics update.\n        ///\n        /// Semantic nodes annotated with this flag will still recieve a11y focus.\n        ///\n        /// Updating this label within the same active route subtree will not cause\n        /// additional announcements.\n        public static SemanticsFlag namesRoute = new SemanticsFlag(_kNamesRouteIndex);\n\n        /// Whether the semantics node is considered hidden.\n        ///\n        /// Hidden elements are currently not visible on screen. They may be covered\n        /// by other elements or positioned outside of the visible area of a viewport.\n        ///\n        /// Hidden elements cannot gain accessibility focus though regular touch. The\n        /// only way they can be focused is by moving the focus to them via linear\n        /// navigation.\n        ///\n        /// Platforms are free to completely ignore hidden elements and new platforms\n        /// are encouraged to do so.\n        ///\n        /// Instead of marking an element as hidden it should usually be excluded from\n        /// the semantics tree altogether. Hidden elements are only included in the\n        /// semantics tree to work around platform limitations and they are mainly\n        /// used to implement accessibility scrolling on iOS.\n        public static SemanticsFlag isHidden = new SemanticsFlag(_kIsHiddenIndex);\n\n        /// Whether the semantics node represents an image.\n        ///\n        /// Both TalkBack and VoiceOver will inform the user the the semantics node\n        /// represents an image.\n        public static SemanticsFlag isImage = new SemanticsFlag(_kIsImageIndex);\n\n        /// Whether the semantics node is a live region.\n        ///\n        /// A live region indicates that updates to semantics node are important.\n        /// Platforms may use this information to make polite announcements to the\n        /// user to inform them of updates to this node.\n        ///\n        /// An example of a live region is a [SnackBar] widget. On Android, A live\n        /// region causes a polite announcement to be generated automatically, even\n        /// if the user does not have focus of the widget.\n        public static SemanticsFlag isLiveRegion = new SemanticsFlag(_kIsLiveRegionIndex);\n\n        /// The semantics node has the quality of either being \"on\" or \"off\".\n        ///\n        /// This flag is mutually exclusive with [hasCheckedState].\n        ///\n        /// For example, a switch has toggled state.\n        ///\n        /// See also:\n        ///\n        ///    * [SemanticsFlag.isToggled], which controls whether the node is \"on\" or \"off\".\n        public static SemanticsFlag hasToggledState = new SemanticsFlag(_kHasToggledStateIndex);\n\n        /// If true, the semantics node is \"on\". If false, the semantics node is\n        /// \"off\".\n        ///\n        /// For example, if a switch is in the on position, [isToggled] is true.\n        ///\n        /// See also:\n        ///\n        ///   * [SemanticsFlag.hasToggledState], which enables a toggled state.\n        public static SemanticsFlag isToggled = new SemanticsFlag(_kIsToggledIndex);\n\n        /// Whether the platform can scroll the semantics node when the user attempts\n        /// to move focus to an offscreen child.\n        ///\n        /// For example, a [ListView] widget has implicit scrolling so that users can\n        /// easily move to the next visible set of children. A [TabBar] widget does\n        /// not have implicit scrolling, so that users can navigate into the tab\n        /// body when reaching the end of the tab bar.\n        public static SemanticsFlag hasImplicitScrolling = new SemanticsFlag(_kHasImplicitScrollingIndex);\n\n        /// The possible semantics flags.\n        ///\n        /// The map's key is the [index] of the flag and the value is the flag itself.\n        public static Dictionary<int, SemanticsFlag> values = new Dictionary<int, SemanticsFlag>{\n    { _kHasCheckedStateIndex, hasCheckedState},\n    { _kIsCheckedIndex, isChecked},\n    { _kIsSelectedIndex, isSelected},\n    { _kIsButtonIndex, isButton},\n    { _kIsTextFieldIndex, isTextField},\n    { _kIsFocusedIndex, isFocused},\n    { _kHasEnabledStateIndex, hasEnabledState},\n    { _kIsEnabledIndex, isEnabled},\n    { _kIsInMutuallyExclusiveGroupIndex, isInMutuallyExclusiveGroup},\n    { _kIsHeaderIndex, isHeader},\n    { _kIsObscuredIndex, isObscured},\n    { _kScopesRouteIndex, scopesRoute},\n    { _kNamesRouteIndex, namesRoute},\n    { _kIsHiddenIndex, isHidden},\n    { _kIsImageIndex, isImage},\n    { _kIsLiveRegionIndex, isLiveRegion},\n    { _kHasToggledStateIndex, hasToggledState},\n    { _kIsToggledIndex, isToggled},\n    { _kHasImplicitScrollingIndex, hasImplicitScrolling},\n  };\n\n        public String toString()\n        {\n            switch (index)\n            {\n                case _kHasCheckedStateIndex:\n                    return \"SemanticsFlag.hasCheckedState\";\n                case _kIsCheckedIndex:\n                    return \"SemanticsFlag.isChecked\";\n                case _kIsSelectedIndex:\n                    return \"SemanticsFlag.isSelected\";\n                case _kIsButtonIndex:\n                    return \"SemanticsFlag.isButton\";\n                case _kIsTextFieldIndex:\n                    return \"SemanticsFlag.isTextField\";\n                case _kIsFocusedIndex:\n                    return \"SemanticsFlag.isFocused\";\n                case _kHasEnabledStateIndex:\n                    return \"SemanticsFlag.hasEnabledState\";\n                case _kIsEnabledIndex:\n                    return \"SemanticsFlag.isEnabled\";\n                case _kIsInMutuallyExclusiveGroupIndex:\n                    return \"SemanticsFlag.isInMutuallyExclusiveGroup\";\n                case _kIsHeaderIndex:\n                    return \"SemanticsFlag.isHeader\";\n                case _kIsObscuredIndex:\n                    return \"SemanticsFlag.isObscured\";\n                case _kScopesRouteIndex:\n                    return \"SemanticsFlag.scopesRoute\";\n                case _kNamesRouteIndex:\n                    return \"SemanticsFlag.namesRoute\";\n                case _kIsHiddenIndex:\n                    return \"SemanticsFlag.isHidden\";\n                case _kIsImageIndex:\n                    return \"SemanticsFlag.isImage\";\n                case _kIsLiveRegionIndex:\n                    return \"SemanticsFlag.isLiveRegion\";\n                case _kHasToggledStateIndex:\n                    return \"SemanticsFlag.hasToggledState\";\n                case _kIsToggledIndex:\n                    return \"SemanticsFlag.isToggled\";\n                case _kHasImplicitScrollingIndex:\n                    return \"SemanticsFlag.hasImplicitScrolling\";\n            }\n            return null;\n        }\n    }\n\n    /// An object that creates [SemanticsUpdate] objects.\n    ///\n    /// Once created, the [SemanticsUpdate] objects can be passed to\n    /// [Window.updateSemantics] to update the semantics conveyed to the user.\n    public class SemanticsUpdateBuilder : NativeFieldWrapperClass2\n    {\n        /// Creates an empty [SemanticsUpdateBuilder] object.\n        //@pragma('vm:entry-point')\n        public SemanticsUpdateBuilder() { _constructor(); }\n        void _constructor()\n        {\n            // native 'SemanticsUpdateBuilder_constructor';\n        }\n\n        /// Update the information associated with the node with the given `id`.\n        ///\n        /// The semantics nodes form a tree, with the root of the tree always having\n        /// an id of zero. The `childrenInTraversalOrder` and `childrenInHitTestOrder`\n        /// are the ids of the nodes that are immediate children of this node. The\n        /// former enumerates children in traversal order, and the latter enumerates\n        /// the same children in the hit test order. The two lists must have the same\n        /// length and contain the same ids. They may only differ in the order the\n        /// ids are listed in. For more information about different child orders, see\n        /// [DebugSemanticsDumpOrder].\n        ///\n        /// The system retains the nodes that are currently reachable from the root.\n        /// A given update need not contain information for nodes that do not change\n        /// in the update. If a node is not reachable from the root after an update,\n        /// the node will be discarded from the tree.\n        ///\n        /// The `flags` are a bit field of [SemanticsFlag]s that apply to this node.\n        ///\n        /// The `actions` are a bit field of [SemanticsAction]s that can be undertaken\n        /// by this node. If the user wishes to undertake one of these actions on this\n        /// node, the [Window.onSemanticsAction] will be called with `id` and one of\n        /// the possible [SemanticsAction]s. Because the semantics tree is maintained\n        /// asynchronously, the [Window.onSemanticsAction] callback might be called\n        /// with an action that is no longer possible.\n        ///\n        /// The `label` is a string that describes this node. The `value` property\n        /// describes the current value of the node as a string. The `increasedValue`\n        /// string will become the `value` string after a [SemanticsAction.increase]\n        /// action is performed. The `decreasedValue` string will become the `value`\n        /// string after a [SemanticsAction.decrease] action is performed. The `hint`\n        /// string describes what result an action performed on this node has. The\n        /// reading direction of all these strings is given by `textDirection`.\n        ///\n        /// The fields 'textSelectionBase' and 'textSelectionExtent' describe the\n        /// currently selected text within `value`.\n        ///\n        /// For scrollable nodes `scrollPosition` describes the current scroll\n        /// position in logical pixel. `scrollExtentMax` and `scrollExtentMin`\n        /// describe the maximum and minimum in-rage values that `scrollPosition` can\n        /// be. Both or either may be infinity to indicate unbound scrolling. The\n        /// value for `scrollPosition` can (temporarily) be outside this range, for\n        /// example during an overscroll. `scrollChildren` is the count of the\n        /// total number of child nodes that contribute semantics and `scrollIndex`\n        /// is the index of the first visible child node that contributes semantics.\n        ///\n        /// The `rect` is the region occupied by this node in its own coordinate\n        /// system.\n        ///\n        /// The `transform` is a matrix that maps this node's coordinate system into\n        /// its parent's coordinate system.\n        public void updateNode(\n            int id = 0,\n          int flags = 0,\n          int actions = 0,\n          int textSelectionBase = 0,\n          int textSelectionExtent = 0,\n          int scrollChildren = 0,\n          int scrollIndex = 0,\n          double scrollPosition = 0.0,\n          double scrollExtentMax = 0.0,\n          double scrollExtentMin = 0.0,\n            Rect rect = null,\n            String label = null,\n            String hint = null,\n            String value = null,\n            String increasedValue = null,\n            String decreasedValue = null,\n            TextDirection textDirection = TextDirection.ltr,\n            List<double> transform = null,\n            List<int> childrenInTraversalOrder = null,\n            List<int> childrenInHitTestOrder = null,\n            //[Obsolete(\"use additionalActions instead\")]\n            List<int> customAcccessibilityActions = null,\n            List<int> additionalActions = null)\n        {\n            if (transform.Count != 16)\n                throw new ArgumentException(\"transform argument must have 16 entries.\");\n            _updateNode(\n              id,\n              flags,\n              actions,\n              textSelectionBase,\n              textSelectionExtent,\n              scrollChildren,\n              scrollIndex,\n              scrollPosition,\n              scrollExtentMax,\n              scrollExtentMin,\n              rect.left,\n              rect.top,\n              rect.right,\n              rect.bottom,\n              label,\n              hint,\n              value,\n              increasedValue,\n              decreasedValue,\n              (int)textDirection,\n              transform,\n              childrenInTraversalOrder,\n              childrenInHitTestOrder,\n              additionalActions ?? customAcccessibilityActions);\n        }\n        void _updateNode(\n           int id,\n           int flags,\n           int actions,\n           int textSelectionBase,\n           int textSelectionExtent,\n           int scrollChildren,\n           int scrollIndex,\n           double scrollPosition,\n           double scrollExtentMax,\n           double scrollExtentMin,\n           double left,\n           double top,\n           double right,\n           double bottom,\n           String label,\n           String hint,\n           String value,\n           String increasedValue,\n           String decreasedValue,\n           int textDirection,\n           List<double> transform,\n           List<int> childrenInTraversalOrder,\n           List<int> childrenInHitTestOrder,\n           List<int> additionalActions)\n        {\n            // native 'SemanticsUpdateBuilder_updateNode';\n        }\n\n        /// Update the custom semantics action associated with the given `id`.\n        ///\n        /// The name of the action exposed to the user is the `label`. For overriden\n        /// standard actions this value is ignored.\n        ///\n        /// The `hint` should describe what happens when an action occurs, not the\n        /// manner in which a tap is accomplished. For example, use \"delete\" instead\n        /// of \"double tap to delete\".\n        ///\n        /// The text direction of the `hint` and `label` is the same as the global\n        /// window.\n        ///\n        /// For overriden standard actions, `overrideId` corresponds with a\n        /// [SemanticsAction.index] value. For custom actions this argument should not be\n        /// provided.\n        void updateCustomAction(int id = 0, String label = \"\", String hint = \"\", int overrideId = -1)\n        {\n            //assert(id != null);\n            //assert(overrideId != null);\n            _updateCustomAction(id, label, hint, overrideId);\n        }\n        void _updateCustomAction(int id, String label, String hint, int overrideId)\n        {\n            // native 'SemanticsUpdateBuilder_updateCustomAction';\n        }\n\n        /// Creates a [SemanticsUpdate] object that encapsulates the updates recorded\n        /// by this object.\n        ///\n        /// The returned object can be passed to [Window.updateSemantics] to actually\n        /// update the semantics retained by the system.\n        public SemanticsUpdate build()\n        {\n            // native 'SemanticsUpdateBuilder_build';\n            return null; // Tmp to resolve build\n        }\n\n    }\n\n    /// An opaque object representing a batch of semantics updates.\n    ///\n    /// To create a SemanticsUpdate object, use a [SemanticsUpdateBuilder].\n    ///\n    /// Semantics updates can be applied to the system's retained semantics tree\n    /// using the [Window.updateSemantics] method.\n    public class SemanticsUpdate : NativeFieldWrapperClass2\n    {\n        /// This class is created by the engine, and should not be instantiated\n        /// or extended directly.\n        ///\n        /// To create a SemanticsUpdate object, use a [SemanticsUpdateBuilder].\n        //@pragma('vm:entry-point')\n        //SemanticsUpdate();\n\n        /// Releases the resources used by this semantics update.\n        ///\n        /// After calling this function, the semantics update is cannot be used\n        /// further.\n        void dispose()\n        {\n            // native 'SemanticsUpdate_dispose';\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Text.cs",
    "content": "﻿using FlutterBinding.Engine.Text;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing static FlutterBinding.Mapping.Helper;\nusing static FlutterBinding.Mapping.Types;\nusing static FlutterBinding.UI.Lerp;\nusing static FlutterBinding.UI.Text;\n\nnamespace FlutterBinding.UI\n{\n\n    /// Whether to slant the glyphs in the font\n    public enum FontStyle\n    {\n        /// Use the upright glyphs\n        normal,\n\n        /// Use glyphs designed for slanting\n        italic,\n    }\n\n    /// The thickness of the glyphs used to draw the text\n    public class FontWeight\n    {\n        private FontWeight(int index)\n        {\n            this.index = index;\n        }\n\n        /// The encoded integer value of this font weight.\n        public readonly int index;\n\n        /// Thin, the least thick\n        public static FontWeight w100 = new FontWeight(0);\n\n        /// Extra-light\n        public static FontWeight w200 = new FontWeight(1);\n\n        /// Light\n        public static FontWeight w300 = new FontWeight(2);\n\n        /// Normal / regular / plain\n        public static FontWeight w400 = new FontWeight(3);\n\n        /// Medium\n        public static FontWeight w500 = new FontWeight(4);\n\n        /// Semi-bold\n        public static FontWeight w600 = new FontWeight(5);\n\n        /// Bold\n        public static FontWeight w700 = new FontWeight(6);\n\n        /// Extra-bold\n        public static FontWeight w800 = new FontWeight(7);\n\n        /// Black, the most thick\n        static FontWeight w900 = new FontWeight(8);\n\n        /// The default font weight.\n        public static FontWeight normal = w400;\n\n        /// A commonly used font weight that is heavier than normal.\n        public static FontWeight bold = w700;\n\n        /// A list of all the font weights.\n        public static List<FontWeight> values = new List<FontWeight>{\n          w100, w200, w300, w400, w500, w600, w700, w800, w900\n        };\n\n        /// Linearly interpolates between two font weights.\n        ///\n        /// Rather than using fractional weights, the interpolation rounds to the\n        /// nearest weight.\n        ///\n        /// Any null values for `a` or `b` are interpreted as equivalent to [normal]\n        /// (also known as [w400]).\n        ///\n        /// The `t` argument represents position on the timeline, with 0.0 meaning\n        /// that the interpolation has not started, returning `a` (or something\n        /// equivalent to `a`), 1.0 meaning that the interpolation has finished,\n        /// returning `b` (or something equivalent to `b`), and values in between\n        /// meaning that the interpolation is at the relevant point on the timeline\n        /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and\n        /// 1.0, so negative values and values greater than 1.0 are valid (and can\n        /// easily be generated by curves such as [Curves.elasticInOut]). The result\n        /// is clamped to the range [w100]–[w900].\n        ///\n        /// Values for `t` are usually obtained from an [Animation<double>], such as\n        /// an [AnimationController].\n        public static FontWeight lerp(FontWeight a, FontWeight b, double t)\n        {\n            //assert(t != null);\n            return values[(int)lerpDouble(a?.index ?? normal.index, b?.index ?? normal.index, t).round().clamp(0, 8)];\n        }\n\n        public String toString()\n        {\n            return new Dictionary<int, String>{\n                { 0,  \"FontWeight.w100\" },\n              { 1, \"FontWeight.w200\" },\n              { 2, \"FontWeight.w300\" },\n             {  3, \"FontWeight.w400\" },\n             {  4, \"FontWeight.w500\" },\n             {  5, \"FontWeight.w600\" },\n              { 6, \"FontWeight.w700\" },\n             {  7, \"FontWeight.w800\" },\n              { 8, \"FontWeight.w900\" },\n            }[index];\n        }\n    }\n\n    /// Whether and how to align text horizontally.\n    // The order of this enum must match the order of the values in RenderStyleConstants.h's ETextAlign.\n    public enum TextAlign\n    {\n        /// Align the text on the left edge of the container.\n        left,\n\n        /// Align the text on the right edge of the container.\n        right,\n\n        /// Align the text in the center of the container.\n        center,\n\n        /// Stretch lines of text that end with a soft line break to fill the width of\n        /// the container.\n        ///\n        /// Lines that end with hard line breaks are aligned towards the [start] edge.\n        justify,\n\n        /// Align the text on the leading edge of the container.\n        ///\n        /// For left-to-right text ([TextDirection.ltr]), this is the left edge.\n        ///\n        /// For right-to-left text ([TextDirection.rtl]), this is the right edge.\n        start,\n\n        /// Align the text on the trailing edge of the container.\n        ///\n        /// For left-to-right text ([TextDirection.ltr]), this is the right edge.\n        ///\n        /// For right-to-left text ([TextDirection.rtl]), this is the left edge.\n        end,\n    }\n\n    /// A horizontal line used for aligning text.\n    public enum TextBaseline\n    {\n        /// The horizontal line used to align the bottom of glyphs for alphabetic characters.\n        alphabetic,\n\n        /// The horizontal line used to align ideographic characters.\n        ideographic,\n    }\n\n    /// A linear decoration to draw near the text.\n    public class TextDecoration\n    {\n        public TextDecoration(int _mask)\n        {\n            this._mask = _mask;\n        }\n\n        /// Creates a decoration that paints the union of all the given decorations.\n        public TextDecoration combine(List<TextDecoration> decorations)\n        {\n            int mask = 0;\n            foreach (TextDecoration decoration in decorations)\n                mask |= decoration._mask;\n            return new TextDecoration(mask);\n        }\n\n        public readonly int _mask;\n\n        /// Whether this decoration will paint at least as much decoration as the given decoration.\n        bool contains(TextDecoration other)\n        {\n            return (_mask | other._mask) == _mask;\n        }\n\n        /// Do not draw a decoration\n        public static TextDecoration none = new TextDecoration(0x0);\n\n        /// Draw a line underneath each line of text\n        public static TextDecoration underline = new TextDecoration(0x1);\n\n        /// Draw a line above each line of text\n        public static TextDecoration overline = new TextDecoration(0x2);\n\n        /// Draw a line through each line of text\n        public static TextDecoration lineThrough = new TextDecoration(0x4);\n\n        public static bool operator ==(TextDecoration text, Object other)\n        {\n            if (!(other is TextDecoration))\n                return false;\n            TextDecoration typedOther = (TextDecoration)other;\n            return text._mask == typedOther._mask;\n        }\n\n        public static bool operator !=(TextDecoration text, Object other) => !(text == other);\n\n        public int hashCode => _mask.GetHashCode();\n\n        public String toString()\n        {\n            if (_mask == 0)\n                return \"TextDecoration.none\";\n            List<String> values = new List<String>();\n            if ((_mask & underline._mask) != 0)\n                values.Add(\"underline\");\n            if ((_mask & overline._mask) != 0)\n                values.Add(\"overline\");\n            if ((_mask & lineThrough._mask) != 0)\n                values.Add(\"lineThrough\");\n            if (values.Count == 1)\n                return $\"TextDecoration.{values[0]}\";\n            return $\"TextDecoration.combine([{string.Join(\", \", values)}])\";\n        }\n    }\n\n    /// The style in which to draw a text decoration\n    public enum TextDecorationStyle\n    {\n        /// Draw a solid line\n        solid,\n\n        /// Draw two lines\n        @double,\n\n        /// Draw a dotted line\n        dotted,\n\n        /// Draw a dashed line\n        dashed,\n\n        /// Draw a sinusoidal line\n        wavy\n    }\n\n\n    /// An opaque object that determines the size, position, and rendering of text.\n    public class TextStyle\n    {\n        /// Creates a new TextStyle object.\n        ///\n        /// * `color`: The color to use when painting the text. If this is specified, `foreground` must be null.\n        /// * `decoration`: The decorations to paint near the text (e.g., an underline).\n        /// * `decorationColor`: The color in which to paint the text decorations.\n        /// * `decorationStyle`: The style in which to paint the text decorations (e.g., dashed).\n        /// * `fontWeight`: The typeface thickness to use when painting the text (e.g., bold).\n        /// * `fontStyle`: The typeface variant to use when drawing the letters (e.g., italics).\n        /// * `fontFamily`: The name of the font to use when painting the text (e.g., Roboto).\n        /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting the text.\n        /// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter.\n        /// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word).\n        /// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box.\n        /// * `height`: The height of this text span, as a multiple of the font size.\n        /// * `locale`: The locale used to select region-specific glyphs.\n        /// * `background`: The paint drawn as a background for the text.\n        /// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null.\n        public TextStyle(\n            Color color = null,\n            TextDecoration decoration = null,\n            Color decorationColor = null,\n            TextDecorationStyle decorationStyle = TextDecorationStyle.solid,\n            FontWeight fontWeight = null,\n            FontStyle fontStyle = FontStyle.normal,\n            TextBaseline textBaseline = TextBaseline.alphabetic,\n            String fontFamily = null,\n            double fontSize = 0.0,\n            double letterSpacing = 0.0,\n            double wordSpacing = 0.0,\n            double height = 0.0,\n            Locale locale = null,\n            Paint background = null,\n            Paint foreground = null,\n            List<Shadow> shadows = null)\n        {\n            //assert(color == null || foreground == null,\n            //        \"Cannot provide both a color and a foreground\\n\" +\n            //        \"The color argument is just a shorthand for 'foreground: new Paint()..color = color'.\"\n            //      );\n            _encoded = _encodeTextStyle(\n              color,\n              decoration,\n              decorationColor,\n              decorationStyle,\n              fontWeight,\n              fontStyle,\n              textBaseline,\n              fontFamily,\n              fontSize,\n              letterSpacing,\n              wordSpacing,\n              height,\n              locale,\n              background,\n              foreground,\n              shadows);\n            _fontFamily = fontFamily ?? \"\";\n            _fontSize = fontSize;\n            _letterSpacing = letterSpacing;\n            _wordSpacing = wordSpacing;\n            _height = height;\n            _locale = locale;\n            _background = background;\n            _foreground = foreground;\n            _shadows = shadows;\n        }\n\n        public List<int> _encoded;\n        public String _fontFamily;\n        public double _fontSize;\n        public double _letterSpacing;\n        public double _wordSpacing;\n        public double _height;\n        public Locale _locale;\n        public Paint _background;\n        public Paint _foreground;\n        public List<Shadow> _shadows;\n\n\n        public static bool operator ==(TextStyle style, Object other)\n        {\n            if (identical(style, other))\n                return true;\n            if (!(other is TextStyle))\n                return false;\n            TextStyle typedOther = (TextStyle)other;\n            if (style._fontFamily != typedOther._fontFamily ||\n               style._fontSize != typedOther._fontSize ||\n                style._letterSpacing != typedOther._letterSpacing ||\n                style._wordSpacing != typedOther._wordSpacing ||\n                style._height != typedOther._height ||\n                style._locale != typedOther._locale ||\n                style._background != typedOther._background ||\n                style._foreground != typedOther._foreground)\n                return false;\n            for (int index = 0; index < style._encoded.Count; index += 1)\n            {\n                if (style._encoded[index] != typedOther._encoded[index])\n                    return false;\n            }\n            if (!Shadow._shadowsListEquals(style._shadows, typedOther._shadows))\n                return false;\n            return true;\n        }\n\n        public static bool operator !=(TextStyle style, Object other) => !(style == other);\n\n        public int hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _letterSpacing, _wordSpacing, _height, _locale, _background, _foreground);\n\n        public String toString()\n        {\n            return \"TextStyle(\" +\n               $\"color: {          ((_encoded[0] & 0x00002) == 0x00002 ? new Color((uint)_encoded[1]).toString() : \"unspecified\") }, \" +\n               $\"decoration: {     ((_encoded[0] & 0x00004) == 0x00004 ? new TextDecoration(_encoded[2]).toString() : \"unspecified\")}, \" +\n               $\"decorationColor:{((_encoded[0] & 0x00008) == 0x00008 ? new Color((uint)_encoded[3]).toString() : \"unspecified\")}, \" +\n               $\"decorationStyle: {((_encoded[0] & 0x00010) == 0x00010 ? ((TextDecorationStyle)(_encoded[4])).ToString() : \"unspecified\")}, \" +\n               $\"fontWeight: {     ((_encoded[0] & 0x00020) == 0x00020 ? FontWeight.values[_encoded[5]].toString() : \"unspecified\")}, \" +\n               $\"fontStyle: {      ((_encoded[0] & 0x00040) == 0x00040 ? ((FontStyle)(_encoded[6])).ToString() : \"unspecified\")}, \" +\n               $\"textBaseline: {   ((_encoded[0] & 0x00080) == 0x00080 ? ((TextBaseline)(_encoded[7])).ToString() : \"unspecified\")}, \" +\n               $\"fontFamily: {     ((_encoded[0] & 0x00100) == 0x00100 ? _fontFamily : \"unspecified\")}, \" +\n               $\"fontSize: {       ((_encoded[0] & 0x00200) == 0x00200 ? _fontSize.ToString() : \"unspecified\")}, \" +\n               $\"letterSpacing: {  ((_encoded[0] & 0x00400) == 0x00400 ? $\"{_letterSpacing}x\" : \"unspecified\")}, \" +\n               $\"wordSpacing: {    ((_encoded[0] & 0x00800) == 0x00800 ? $\"{_wordSpacing}x\" : \"unspecified\")}, \" +\n               $\"height: {         ((_encoded[0] & 0x01000) == 0x01000 ? $\"{_height}x\" : \"unspecified\")}, \" +\n               $\"locale: {         ((_encoded[0] & 0x02000) == 0x02000 ? _locale.toString() : \"unspecified\")}, \" +\n               $\"background: {     ((_encoded[0] & 0x04000) == 0x04000 ? _background.toString() : \"unspecified\")}, \" +\n               $\"foreground: {     ((_encoded[0] & 0x08000) == 0x08000 ? _foreground.toString() : \"unspecified\")}, \" +\n               $\"shadows: {        ((_encoded[0] & 0x10000) == 0x10000 ? _shadows.ToString() : \"unspecified\")}\" +\n             \")\";\n        }\n    }\n\n\n    /// An opaque object that determines the configuration used by\n    /// [ParagraphBuilder] to position lines within a [Paragraph] of text.\n    public class ParagraphStyle\n    {\n        /// Creates a new ParagraphStyle object.\n        ///\n        /// * `textAlign`: The alignment of the text within the lines of the\n        ///   paragraph. If the last line is ellipsized (see `ellipsis` below), the\n        ///   alignment is applied to that line after it has been truncated but before\n        ///   the ellipsis has been added.\n        //   See: https://github.com/flutter/flutter/issues/9819\n        ///\n        /// * `textDirection`: The directionality of the text, left-to-right (e.g.\n        ///   Norwegian) or right-to-left (e.g. Hebrew). This controls the overall\n        ///   directionality of the paragraph, as well as the meaning of\n        ///   [TextAlign.start] and [TextAlign.end] in the `textAlign` field.\n        ///\n        /// * `fontWeight`: The typeface thickness to use when painting the text\n        ///   (e.g., bold).\n        ///\n        /// * `fontStyle`: The typeface variant to use when drawing the letters (e.g.,\n        ///   italics).\n        ///\n        /// * `maxLines`: The maximum number of lines painted. Lines beyond this\n        ///   number are silently dropped. For example, if `maxLines` is 1, then only\n        ///   one line is rendered. If `maxLines` is null, but `ellipsis` is not null,\n        ///   then lines after the first one that overflows the width constraints are\n        ///   dropped. The width constraints are those set in the\n        ///   [ParagraphConstraints] object passed to the [Paragraph.layout] method.\n        ///\n        /// * `fontFamily`: The name of the font to use when painting the text (e.g.,\n        ///   Roboto).\n        ///\n        /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting\n        ///   the text.\n        ///\n        /// * `lineHeight`: The minimum height of the line boxes, as a multiple of the\n        ///   font size.\n        ///\n        /// * `ellipsis`: String used to ellipsize overflowing text. If `maxLines` is\n        ///   not null, then the `ellipsis`, if any, is applied to the last rendered\n        ///   line, if that line overflows the width constraints. If `maxLines` is\n        ///   null, then the `ellipsis` is applied to the first line that overflows\n        ///   the width constraints, and subsequent lines are dropped. The width\n        ///   constraints are those set in the [ParagraphConstraints] object passed to\n        ///   the [Paragraph.layout] method. The empty string and the null value are\n        ///   considered equivalent and turn off this behavior.\n        ///\n        /// * `locale`: The locale used to select region-specific glyphs.\n        public ParagraphStyle(\n            TextAlign textAlign = TextAlign.left,\n            TextDirection textDirection = TextDirection.ltr,\n            FontWeight fontWeight = null,\n            FontStyle fontStyle = FontStyle.normal,\n            int maxLines = 0,\n            String fontFamily = \"\",\n            double fontSize = 0.0,\n            double lineHeight = 0.0,\n            String ellipsis = \"\",\n            Locale locale = null)\n        {\n            if (fontWeight == null)\n                fontWeight = FontWeight.normal;\n\n            if (locale == null)\n                locale = new Locale(\"\");\n\n            _encoded = _encodeParagraphStyle(\n          textAlign,\n          textDirection,\n          fontWeight,\n          fontStyle,\n          maxLines,\n          fontFamily,\n          fontSize,\n          lineHeight,\n          ellipsis,\n          locale);\n            _fontFamily = fontFamily;\n            _fontSize = fontSize;\n            _lineHeight = lineHeight;\n            _ellipsis = ellipsis;\n            _locale = locale;\n        }\n        public readonly List<int> _encoded;\n        public readonly String _fontFamily;\n        public readonly double _fontSize;\n        public readonly double _lineHeight;\n        public readonly String _ellipsis;\n        public readonly Locale _locale;\n\n        public static bool operator ==(ParagraphStyle paragraph, Object other)\n        {\n            if (identical(paragraph, other))\n                return true;\n            if (other.GetType() != paragraph.GetType())\n                return false;\n            ParagraphStyle typedOther = (ParagraphStyle)other;\n            if (paragraph._fontFamily != typedOther._fontFamily ||\n                paragraph._fontSize != typedOther._fontSize ||\n                paragraph._lineHeight != typedOther._lineHeight ||\n                paragraph._ellipsis != typedOther._ellipsis ||\n                paragraph._locale != typedOther._locale)\n                return false;\n            for (int index = 0; index < paragraph._encoded.Count; index += 1)\n            {\n                if (paragraph._encoded[index] != typedOther._encoded[index])\n                    return false;\n            }\n            return true;\n        }\n\n        public static bool operator !=(ParagraphStyle paragraph, Object other) => !(paragraph == other);\n\n        public int hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _lineHeight, _ellipsis, _locale);\n\n        String toString()\n        {\n            return \"{GetType().ToString()}(\" +\n                       $\"textAlign: {     ((_encoded[0] & 0x002) == 0x002 ? ((TextAlign)(_encoded[1])).ToString() : \"unspecified\")}, \" +\n                       $\"textDirection: { ((_encoded[0] & 0x004) == 0x004 ? ((TextDirection)(_encoded[2])).ToString() : \"unspecified\")}, \" +\n                       $\"fontWeight: {    ((_encoded[0] & 0x008) == 0x008 ? (FontWeight.values[_encoded[3]]).ToString() : \"unspecified\")}, \" +\n                       $\"fontStyle: {     ((_encoded[0] & 0x010) == 0x010 ? ((FontStyle)(_encoded[4])).ToString() : \"unspecified\")}, \" +\n                       $\"maxLines: {      ((_encoded[0] & 0x020) == 0x020 ? _encoded[5].ToString() : \"unspecified\")}, \" +\n                       $\"fontFamily: {    ((_encoded[0] & 0x040) == 0x040 ? _fontFamily.ToString() : \"unspecified\")}, \" +\n                       $\"fontSize: {      ((_encoded[0] & 0x080) == 0x080 ? _fontSize.ToString() : \"unspecified\")}, \" +\n                       $\"lineHeight: {    ((_encoded[0] & 0x100) == 0x100 ? $\"{_lineHeight}x\" : \"unspecified\")}, \" +\n                       $\"ellipsis: {      ((_encoded[0] & 0x200) == 0x200 ? $\"\\\"{_ellipsis}\\\"\" : \"unspecified\")}, \" +\n                       $\"locale: {        ((_encoded[0] & 0x400) == 0x400 ? _locale.toString() : \"unspecified\")}\" +\n                     \")\";\n        }\n    }\n\n    /// A direction in which text flows.\n    ///\n    /// Some languages are written from the left to the right (for example, English,\n    /// Tamil, or Chinese), while others are written from the right to the left (for\n    /// example Aramaic, Hebrew, or Urdu). Some are also written in a mixture, for\n    /// example Arabic is mostly written right-to-left, with numerals written\n    /// left-to-right.\n    ///\n    /// The text direction must be provided to APIs that render text or lay out\n    /// boxes horizontally, so that they can determine which direction to start in:\n    /// either right-to-left, [TextDirection.rtl]; or left-to-right,\n    /// [TextDirection.ltr].\n    ///\n    /// ## Design discussion\n    ///\n    /// Flutter is designed to address the needs of applications written in any of\n    /// the world's currently-used languages, whether they use a right-to-left or\n    /// left-to-right writing direction. Flutter does not support other writing\n    /// modes, such as vertical text or boustrophedon text, as these are rarely used\n    /// in computer programs.\n    ///\n    /// It is common when developing user interface frameworks to pick a default\n    /// text direction — typically left-to-right, the direction most familiar to the\n    /// engineers working on the framework — because this simplifies the development\n    /// of applications on the platform. Unfortunately, this frequently results in\n    /// the platform having unexpected left-to-right biases or assumptions, as\n    /// engineers will typically miss places where they need to support\n    /// right-to-left text. This then results in bugs that only manifest in\n    /// right-to-left environments.\n    ///\n    /// In an effort to minimize the extent to which Flutter experiences this\n    /// category of issues, the lowest levels of the Flutter framework do not have a\n    /// default text reading direction. Any time a reading direction is necessary,\n    /// for example when text is to be displayed, or when a\n    /// writing-direction-dependent value is to be interpreted, the reading\n    /// direction must be explicitly specified. Where possible, such as in `switch`\n    /// statements, the right-to-left case is listed first, to avoid the impression\n    /// that it is an afterthought.\n    ///\n    /// At the higher levels (specifically starting at the widgets library), an\n    /// ambient [Directionality] is introduced, which provides a default. Thus, for\n    /// instance, a [Text] widget in the scope of a [MaterialApp] widget does not\n    /// need to be given an explicit writing direction. The [Directionality.of]\n    /// static method can be used to obtain the ambient text direction for a\n    /// particular [BuildContext].\n    ///\n    /// ### Known left-to-right biases in Flutter\n    ///\n    /// Despite the design intent described above, certain left-to-right biases have\n    /// nonetheless crept into Flutter's design. These include:\n    ///\n    ///  * The [Canvas] origin is at the top left, and the x-axis increases in a\n    ///    left-to-right direction.\n    ///\n    ///  * The default localization in the widgets and material libraries is\n    ///    American English, which is left-to-right.\n    ///\n    /// ### Visual properties vs directional properties\n    ///\n    /// Many classes in the Flutter framework are offered in two versions, a\n    /// visually-oriented variant, and a text-direction-dependent variant. For\n    /// example, [EdgeInsets] is described in terms of top, left, right, and bottom,\n    /// while [EdgeInsetsDirectional] is described in terms of top, start, end, and\n    /// bottom, where start and end correspond to right and left in right-to-left\n    /// text and left and right in left-to-right text.\n    ///\n    /// There are distinct use cases for each of these variants.\n    ///\n    /// Text-direction-dependent variants are useful when developing user interfaces\n    /// that should \"flip\" with the text direction. For example, a paragraph of text\n    /// in English will typically be left-aligned and a quote will be indented from\n    /// the left, while in Arabic it will be right-aligned and indented from the\n    /// right. Both of these cases are described by the direction-dependent\n    /// [TextAlign.start] and [EdgeInsetsDirectional.start].\n    ///\n    /// In contrast, the visual variants are useful when the text direction is known\n    /// and not affected by the reading direction. For example, an application\n    /// giving driving directions might show a \"turn left\" arrow on the left and a\n    /// \"turn right\" arrow on the right — and would do so whether the application\n    /// was localized to French (left-to-right) or Hebrew (right-to-left).\n    ///\n    /// In practice, it is also expected that many developers will only be\n    /// targeting one language, and in that case it may be simpler to think in\n    /// visual terms.\n    // The order of this enum must match the order of the values in TextDirection.h's TextDirection.\n    public enum TextDirection\n    {\n        /// The text flows from right to left (e.g. Arabic, Hebrew).\n        rtl,\n\n        /// The text flows from left to right (e.g., English, French).\n        ltr,\n    }\n\n    /// A rectangle enclosing a run of text.\n    ///\n    /// This is similar to [Rect] but includes an inherent [TextDirection].\n    public class TextBox\n    {\n        /// Creates an object that describes a box containing text.\n        public static TextBox fromLTRBD(double left,\n                                        double top,\n                                        double right,\n                                        double bottom,\n                                        int direction)\n        {\n            return new TextBox(left, top, right, bottom, direction);\n        }\n\n        //@pragma('vm:entry-point')\n        public TextBox(double left,\n                        double top,\n                        double right,\n                        double bottom,\n                       int directionIndex)\n        {\n            this.left = left;\n            this.top = top;\n            this.right = right;\n            this.bottom = bottom;\n            direction = (TextDirection)directionIndex;\n        }\n        /// The left edge of the text box, irrespective of direction.\n        ///\n        /// To get the leading edge (which may depend on the [direction]), consider [start].\n        public readonly double left;\n\n        /// The top edge of the text box.\n        public readonly double top;\n\n        /// The right edge of the text box, irrespective of direction.\n        ///\n        /// To get the trailing edge (which may depend on the [direction]), consider [end].\n        public readonly double right;\n\n        /// The bottom edge of the text box.\n        public readonly double bottom;\n\n        /// The direction in which text inside this box flows.\n        public readonly TextDirection direction;\n\n        /// Returns a rect of the same size as this box.\n        public Rect toRect() => Rect.fromLTRB(left, top, right, bottom);\n\n        /// The [left] edge of the box for left-to-right text; the [right] edge of the box for right-to-left text.\n        ///\n        /// See also:\n        ///\n        ///  * [direction], which specifies the text direction.\n        public double start => (direction == TextDirection.ltr) ? left : right;\n\n        /// The [right] edge of the box for left-to-right text; the [left] edge of the box for right-to-left text.\n        ///\n        /// See also:\n        ///\n        ///  * [direction], which specifies the text direction.\n        public double end => (direction == TextDirection.ltr) ? right : left;\n\n        public static bool operator ==(TextBox text, Object other)\n        {\n            if (identical(text, other))\n                return true;\n            if (other.GetType() != text.GetType())\n                return false;\n            TextBox typedOther = (TextBox)other;\n            return typedOther.left == text.left\n                && typedOther.top == text.top\n                && typedOther.right == text.right\n                && typedOther.bottom == text.bottom\n                && typedOther.direction == text.direction;\n        }\n\n        public static bool operator !=(TextBox text, Object other) => !(text == other);\n\n        public int hashCode => hashValues(left, top, right, bottom, direction);\n\n        public String toString() => $\"TextBox.fromLTRBD({left.toStringAsFixed(1)}, {top.toStringAsFixed(1)}, {right.toStringAsFixed(1)}, {bottom.toStringAsFixed(1)}, {direction})\";\n    }\n\n    /// Whether a [TextPosition] is visually upstream or downstream of its offset.\n    ///\n    /// For example, when a text position exists at a line break, a single offset has\n    /// two visual positions, one prior to the line break (at the end of the first\n    /// line) and one after the line break (at the start of the second line). A text\n    /// affinity disambiguates between those cases. (Something similar happens with\n    /// between runs of bidirectional text.)\n    public enum TextAffinity\n    {\n        /// The position has affinity for the upstream side of the text position.\n        ///\n        /// For example, if the offset of the text position is a line break, the\n        /// position represents the end of the first line.\n        upstream,\n\n        /// The position has affinity for the downstream side of the text position.\n        ///\n        /// For example, if the offset of the text position is a line break, the\n        /// position represents the start of the second line.\n        downstream,\n    }\n\n    /// A visual position in a string of text.\n    public class TextPosition\n    {\n        /// Creates an object representing a particular position in a string.\n        ///\n        /// The arguments must not be null (so the [offset] argument is required).\n        public TextPosition(int offset = 0,\n          TextAffinity affinity = TextAffinity.downstream)\n        {\n            //: assert(offset != null),\n            //assert(affinity != null);\n            this.offset = offset;\n            this.affinity = affinity;\n        }\n        /// The index of the character that immediately follows the position.\n        ///\n        /// For example, given the string `'Hello'`, offset 0 represents the cursor\n        /// being before the `H`, while offset 5 represents the cursor being just\n        /// after the `o`.\n        public int offset;\n\n        /// If the offset has more than one visual location (e.g., occurs at a line\n        /// break), which of the two locations is represented by this position.\n        ///\n        /// For example, if the text `'AB'` had a forced line break between the `A`\n        /// and the `B`, then the downstream affinity at offset 1 represents the\n        /// cursor being just after the `A` on the first line, while the upstream\n        /// affinity at offset 1 represents the cursor being just before the `B` on\n        /// the first line.\n        public TextAffinity affinity;\n\n        public static bool operator ==(TextPosition position, Object other)\n        {\n            if (other.GetType() != position.GetType())\n                return false;\n            TextPosition typedOther = (TextPosition)other;\n            return typedOther.offset == position.offset\n                && typedOther.affinity == position.affinity;\n        }\n\n        public static bool operator !=(TextPosition position, Object other) => !(position == other);\n\n        public int hashCode => hashValues(offset, affinity);\n\n        public String toString()\n        {\n            return $\"{GetType().ToString()}(offset: {offset}, affinity: {affinity})\";\n        }\n    }\n\n    /// Layout constraints for [Paragraph] objects.\n    ///\n    /// Instances of this class are typically used with [Paragraph.layout].\n    ///\n    /// The only constraint that can be specified is the [width]. See the discussion\n    /// at [width] for more details.\n    public class ParagraphConstraints\n    {\n        /// Creates constraints for laying out a pargraph.\n        ///\n        /// The [width] argument must not be null.\n        public ParagraphConstraints(double width = 0.0) //: assert(width != null);\n        {\n            this.width = width;\n        }\n\n        /// The width the paragraph should use whey computing the positions of glyphs.\n        ///\n        /// If possible, the paragraph will select a soft line break prior to reaching\n        /// this width. If no soft line break is available, the paragraph will select\n        /// a hard line break prior to reaching this width. If that would force a line\n        /// break without any characters having been placed (i.e. if the next\n        /// character to be laid out does not fit within the given width constraint)\n        /// then the next character is allowed to overflow the width constraint and a\n        /// forced line break is placed after it (even if an explicit line break\n        /// follows).\n        ///\n        /// The width influences how ellipses are applied. See the discussion at [new\n        /// ParagraphStyle] for more details.\n        ///\n        /// This width is also used to position glyphs according to the [TextAlign]\n        /// alignment described in the [ParagraphStyle] used when building the\n        /// [Paragraph] with a [ParagraphBuilder].\n        public readonly double width;\n\n        public static bool operator ==(ParagraphConstraints constraints, Object other)\n        {\n            if (other.GetType() != constraints.GetType())\n                return false;\n            ParagraphConstraints typedOther = (ParagraphConstraints)other;\n            return typedOther.width == constraints.width;\n        }\n\n        public static bool operator !=(ParagraphConstraints constraints, Object other) => !(constraints == other);\n\n        public int hashCode => width.GetHashCode();\n\n        public String toString() => $\"{GetType().ToString()}(width: {width})\";\n    }\n\n    /// A paragraph of text.\n    ///\n    /// A paragraph retains the size and position of each glyph in the text and can\n    /// be efficiently resized and painted.\n    ///\n    /// To create a [Paragraph] object, use a [ParagraphBuilder].\n    ///\n    /// Paragraphs can be displayed on a [Canvas] using the [Canvas.drawParagraph]\n    /// method.\n    public class Paragraph : NativeParagraph\n    {\n        /// This class is created by the engine, and should not be instantiated\n        /// or extended directly.\n        ///\n        /// To create a [Paragraph] object, use a [ParagraphBuilder].\n        //@pragma('vm:entry-point')\n        public Paragraph() { }\n\n        /// The amount of horizontal space this paragraph occupies.\n        ///\n        /// Valid only after [layout] has been called.\n        public double width => this.Width;\n\n        /// The amount of vertical space this paragraph occupies.\n        ///\n        /// Valid only after [layout] has been called.\n        public double height => this.Height;\n\n        /// The minimum width that this paragraph could be without failing to paint\n        /// its contents within itself.\n        ///\n        /// Valid only after [layout] has been called.\n        public double minIntrinsicWidth => 0.0; // native 'Paragraph_minIntrinsicWidth';\n\n        /// Returns the smallest width beyond which increasing the width never\n        /// decreases the height.\n        ///\n        /// Valid only after [layout] has been called.\n        public double maxIntrinsicWidth => 0.0; // native 'Paragraph_maxIntrinsicWidth';\n\n        /// The distance from the top of the paragraph to the alphabetic\n        /// baseline of the first line, in logical pixels.\n        public double alphabeticBaseline => 0.0; // native 'Paragraph_alphabeticBaseline';\n\n        /// The distance from the top of the paragraph to the ideographic\n        /// baseline of the first line, in logical pixels.\n        public double ideographicBaseline => 0.0; // native 'Paragraph_ideographicBaseline';\n\n        /// True if there is more vertical content, but the text was truncated, either\n        /// because we reached `maxLines` lines of text or because the `maxLines` was\n        /// null, `ellipsis` was not null, and one of the lines exceeded the width\n        /// constraint.\n        ///\n        /// See the discussion of the `maxLines` and `ellipsis` arguments at [new\n        /// ParagraphStyle].\n        public bool didExceedMaxLines => false; // native 'Paragraph_didExceedMaxLines';\n\n        /// Computes the size and position of each glyph in the paragraph.\n        ///\n        /// The [ParagraphConstraints] control how wide the text is allowed to be.\n        public void layout(ParagraphConstraints constraints) => _layout(constraints.width);\n        void _layout(double width)\n        {\n            this.Layout(width);\n            // [DONE] native 'Paragraph_layout';\n        }\n\n        /// Returns a list of text boxes that enclose the given text range.\n        public List<TextBox> getBoxesForRange(int start, int end)\n        {\n            // native 'Paragraph_getRectsForRange';\n            return null; // Tmp to resolve build\n        }\n\n        /// Returns the text position closest to the given offset.\n        TextPosition getPositionForOffset(Offset offset)\n        {\n            List<int> encoded = _getPositionForOffset(offset.dx, offset.dy);\n            return new TextPosition(offset: encoded[0], affinity: (TextAffinity)encoded[1]);\n        }\n        List<int> _getPositionForOffset(double dx, double dy)\n        {\n            // native 'Paragraph_getPositionForOffset';\n            return null; // Tmp to resolve build\n        }\n\n        /// Returns the [start, end] of the word at the given offset. Characters not\n        /// part of a word, such as spaces, symbols, and punctuation, have word breaks\n        /// on both sides. In such cases, this method will return [offset, offset+1].\n        /// Word boundaries are defined more precisely in Unicode Standard Annex #29\n        /// http://www.unicode.org/reports/tr29/#Word_Boundaries\n        public List<int> getWordBoundary(int offset)\n        {\n            // native 'Paragraph_getWordBoundary';\n            return null; // Tmp to resolve build\n        }\n\n        // Redirecting the paint function in this way solves some dependency problems\n        // in the C++ code. If we straighten out the C++ dependencies, we can remove\n        // this indirection.\n        public void _paint(SkiaSharp.SKCanvas canvas, double x, double y)\n        {\n            this.Paint(canvas, x, y);\n            // [DONE] native 'Paragraph_paint';\n        }\n    }\n\n    /// Builds a [Paragraph] containing text with the given styling information.\n    ///\n    /// To set the paragraph's alignment, truncation, and ellipsising behavior, pass\n    /// an appropriately-configured [ParagraphStyle] object to the [new\n    /// ParagraphBuilder] constructor.\n    ///\n    /// Then, call combinations of [pushStyle], [addText], and [pop] to add styled\n    /// text to the object.\n    ///\n    /// Finally, call [build] to obtain the constructed [Paragraph] object. After\n    /// this point, the builder is no longer usable.\n    ///\n    /// After constructing a [Paragraph], call [Paragraph.layout] on it and then\n    /// paint it with [Canvas.drawParagraph].\n    public class ParagraphBuilder : NativeParagraphBuilder\n    {\n\n        /// Creates a [ParagraphBuilder] object, which is used to create a\n        /// [Paragraph].\n        //@pragma('vm:entry-point')\n        public ParagraphBuilder(ParagraphStyle style) : base(style._encoded, style._fontFamily, style._fontSize, style._lineHeight, style._ellipsis, _encodeLocale(style._locale))\n        {\n            // _constructor();\n        }\n        void _constructor(List<int> encoded, String fontFamily, double fontSize, double lineHeight, String ellipsis, String locale)\n        {\n            // Completed by base contruction\n            // [DONE] native 'ParagraphBuilder_constructor';\n        }\n\n        /// Applies the given style to the added text until [pop] is called.\n        ///\n        /// See [pop] for details.\n        void pushStyle(TextStyle style) => _pushStyle(style._encoded, style._fontFamily, style._fontSize, style._letterSpacing, style._wordSpacing, style._height, _encodeLocale(style._locale), style._background?._objects, style._background?._data, style._foreground?._objects, style._foreground?._data, Shadow._encodeShadows(style._shadows));\n        void _pushStyle(List<int> encoded, String fontFamily, double fontSize, double letterSpacing, double wordSpacing, double height, String locale, List<dynamic> backgroundObjects, ByteData backgroundData, List<dynamic> foregroundObjects, ByteData foregroundData, ByteData shadowsData)\n        {\n            // native 'ParagraphBuilder_pushStyle';\n        }\n\n        static String _encodeLocale(Locale locale) => locale?.toString() ?? \"\";\n\n        /// Ends the effect of the most recent call to [pushStyle].\n        ///\n        /// Internally, the paragraph builder maintains a stack of text styles. Text\n        /// added to the paragraph is affected by all the styles in the stack. Calling\n        /// [pop] removes the topmost style in the stack, leaving the remaining styles\n        /// in effect.\n        public void pop()\n        {\n            // native 'ParagraphBuilder_pop';\n        }\n\n        /// Adds the given text to the paragraph.\n        ///\n        /// The text will be styled according to the current stack of text styles.\n        public void addText(String text)\n        {\n            String error = _addText(text);\n            if (error != null)\n                throw new ArgumentException(error);\n        }\n        String _addText(String text)\n        {\n            return this.AddText(text);\n            // [DONE] native 'ParagraphBuilder_addText';\n        }\n\n        /// Applies the given paragraph style and returns a [Paragraph] containing the\n        /// added text and associated styling.\n        ///\n        /// After calling this function, the paragraph builder object is invalid and\n        /// cannot be used further.\n        public Paragraph build()\n        {\n            return this.Build();\n            // [DONE] native 'ParagraphBuilder_build';\n        }\n    }\n\n    public static class Text\n    {\n        /// Loads a font from a buffer and makes it available for rendering text.\n        ///\n        /// * `list`: A list of bytes containing the font file.\n        /// * `fontFamily`: The family name used to identify the font in text styles.\n        ///  If this is not provided, then the family name will be extracted from the font file.\n        static Task loadFontFromList(List<int> list, String fontFamily = \"\")\n        {\n            return _futurize(\n              (_Callback callback) => _loadFontFromList(list, callback, fontFamily)\n            );\n        }\n\n        static String _loadFontFromList(List<int> list, _Callback callback, String fontFamily)\n        {\n            // native 'loadFontFromList';\n            return string.Empty; // Tmp to resolve build\n        }\n\n        // This encoding must match the C++ version ParagraphBuilder::build.\n        //\n        // The encoded array buffer has 5 elements.\n        //\n        //  - Element 0: A bit mask indicating which fields are non-null.\n        //    Bit 0 is unused. Bits 1-n are set if the corresponding index in the\n        //    encoded array is non-null.  The remaining bits represent fields that\n        //    are passed separately from the array.\n        //\n        //  - Element 1: The enum index of the |textAlign|.\n        //\n        //  - Element 2: The index of the |fontWeight|.\n        //\n        //  - Element 3: The enum index of the |fontStyle|.\n        //\n        //  - Element 4: The value of |maxLines|.\n        //\n        public static List<int> _encodeParagraphStyle(\n          TextAlign textAlign,\n          TextDirection textDirection,\n          FontWeight fontWeight,\n          FontStyle fontStyle,\n          int maxLines,\n          String fontFamily,\n          double fontSize,\n          double lineHeight,\n          String ellipsis,\n          Locale locale)\n        {\n            List<int> result = new List<int>(6); // also update paragraph_builder.cc\n            for (var i = 0; i <= 6; i++)\n                result.Add(0);\n\n            if (textAlign != null)\n            {\n                result[0] |= 1 << 1;\n                result[1] = (int)textAlign;\n            }\n            if (textDirection != null)\n            {\n                result[0] |= 1 << 2;\n                result[2] = (int)textDirection;\n            }\n            if (fontWeight != null)\n            {\n                result[0] |= 1 << 3;\n                result[3] = fontWeight.index;\n            }\n            if (fontStyle != null)\n            {\n                result[0] |= 1 << 4;\n                result[4] = (int)fontStyle;\n            }\n            if (maxLines != null)\n            {\n                result[0] |= 1 << 5;\n                result[5] = maxLines;\n            }\n            if (fontFamily != null)\n            {\n                result[0] |= 1 << 6;\n                // Passed separately to native.\n            }\n            if (fontSize != null)\n            {\n                result[0] |= 1 << 7;\n                // Passed separately to native.\n            }\n            if (lineHeight != null)\n            {\n                result[0] |= 1 << 8;\n                // Passed separately to native.\n            }\n            if (ellipsis != null)\n            {\n                result[0] |= 1 << 9;\n                // Passed separately to native.\n            }\n            if (locale != null)\n            {\n                result[0] |= 1 << 10;\n                // Passed separately to native.\n            }\n            return result;\n        }\n\n        // This encoding must match the C++ version of ParagraphBuilder::pushStyle.\n        //\n        // The encoded array buffer has 8 elements.\n        //\n        //  - Element 0: A bit field where the ith bit indicates wheter the ith element\n        //    has a non-null value. Bits 8 to 12 indicate whether |fontFamily|,\n        //    |fontSize|, |letterSpacing|, |wordSpacing|, and |height| are non-null,\n        //    respectively. Bit 0 is unused.\n        //\n        //  - Element 1: The |color| in ARGB with 8 bits per channel.\n        //\n        //  - Element 2: A bit field indicating which text decorations are present in\n        //    the |textDecoration| list. The ith bit is set if there's a TextDecoration\n        //    with enum index i in the list.\n        //\n        //  - Element 3: The |decorationColor| in ARGB with 8 bits per channel.\n        //\n        //  - Element 4: The bit field of the |decorationStyle|.\n        //\n        //  - Element 5: The index of the |fontWeight|.\n        //\n        //  - Element 6: The enum index of the |fontStyle|.\n        //\n        //  - Element 7: The enum index of the |textBaseline|.\n        //\n        public static List<int> _encodeTextStyle(\n          Color color,\n          TextDecoration decoration,\n          Color decorationColor,\n          TextDecorationStyle decorationStyle,\n          FontWeight fontWeight,\n          FontStyle fontStyle,\n          TextBaseline textBaseline,\n          String fontFamily,\n          double fontSize,\n          double letterSpacing,\n          double wordSpacing,\n          double height,\n          Locale locale,\n          Paint background,\n          Paint foreground,\n          List<Shadow> shadows\n        )\n        {\n            List<int> result = new List<int>(8);\n            if (color != null)\n            {\n                result[0] |= 1 << 1;\n                result[1] = (int)color.value;\n            }\n            if (decoration != null)\n            {\n                result[0] |= 1 << 2;\n                result[2] = decoration._mask;\n            }\n            if (decorationColor != null)\n            {\n                result[0] |= 1 << 3;\n                result[3] = (int)decorationColor.value;\n            }\n            if (decorationStyle != null)\n            {\n                result[0] |= 1 << 4;\n                result[4] = (int)decorationStyle;\n            }\n            if (fontWeight != null)\n            {\n                result[0] |= 1 << 5;\n                result[5] = fontWeight.index;\n            }\n            if (fontStyle != null)\n            {\n                result[0] |= 1 << 6;\n                result[6] = (int)fontStyle;\n            }\n            if (textBaseline != null)\n            {\n                result[0] |= 1 << 7;\n                result[7] = (int)textBaseline;\n            }\n            if (fontFamily != null)\n            {\n                result[0] |= 1 << 8;\n                // Passed separately to native.\n            }\n            if (fontSize != null)\n            {\n                result[0] |= 1 << 9;\n                // Passed separately to native.\n            }\n            if (letterSpacing != null)\n            {\n                result[0] |= 1 << 10;\n                // Passed separately to native.\n            }\n            if (wordSpacing != null)\n            {\n                result[0] |= 1 << 11;\n                // Passed separately to native.\n            }\n            if (height != null)\n            {\n                result[0] |= 1 << 12;\n                // Passed separately to native.\n            }\n            if (locale != null)\n            {\n                result[0] |= 1 << 13;\n                // Passed separately to native.\n            }\n            if (background != null)\n            {\n                result[0] |= 1 << 14;\n                // Passed separately to native.\n            }\n            if (foreground != null)\n            {\n                result[0] |= 1 << 15;\n                // Passed separately to native.\n            }\n            if (shadows != null)\n            {\n                result[0] |= 1 << 16;\n                // Passed separately to native.\n            }\n            return result;\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "FlutterBinding/UI/Window.cs",
    "content": "﻿using FlutterBinding.Engine;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static FlutterBinding.Mapping.Types;\n\nnamespace FlutterBinding.UI\n{\n    /// Signature of callbacks that have no arguments and return no data.\n    public delegate void VoidCallback();\n\n    /// Signature for [Window.onBeginFrame].\n    public delegate void FrameCallback(Duration duration);\n\n    /// Signature for [Window.onPointerDataPacket].\n    public delegate void PointerDataPacketCallback(PointerDataPacket packet);\n\n    /// Signature for [Window.onSemanticsAction].\n    public delegate void SemanticsActionCallback(int id, SemanticsAction action, ByteData args);\n\n    /// Signature for responses to platform messages.\n    ///\n    /// Used as a parameter to [Window.sendPlatformMessage] and\n    /// [Window.onPlatformMessage].\n    public delegate void PlatformMessageResponseCallback(ByteData data);\n\n    /// Signature for [Window.onPlatformMessage].\n    public delegate void PlatformMessageCallback(String name, ByteData data, PlatformMessageResponseCallback callback);\n\n    /// States that an application can be in.\n    ///\n    /// The values below describe notifications from the operating system.\n    /// Applications should not expect to always receive all possible\n    /// notifications. For example, if the users pulls out the battery from the\n    /// device, no notification will be sent before the application is suddenly\n    /// terminated, along with the rest of the operating system.\n    ///\n    /// See also:\n    ///\n    ///  * [WidgetsBindingObserver], for a mechanism to observe the lifecycle state\n    ///    from the widgets layer.\n    public enum AppLifecycleState\n    {\n        /// The application is visible and responding to user input.\n        resumed,\n\n        /// The application is in an inactive state and is not receiving user input.\n        ///\n        /// On iOS, this state corresponds to an app or the Flutter host view running\n        /// in the foreground inactive state. Apps transition to this state when in\n        /// a phone call, responding to a TouchID request, when entering the app\n        /// switcher or the control center, or when the UIViewController hosting the\n        /// Flutter app is transitioning.\n        ///\n        /// On Android, this corresponds to an app or the Flutter host view running\n        /// in the foreground inactive state.  Apps transition to this state when\n        /// another activity is focused, such as a split-screen app, a phone call,\n        /// a picture-in-picture app, a system dialog, or another window.\n        ///\n        /// Apps in this state should assume that they may be [paused] at any time.\n        inactive,\n\n        /// The application is not currently visible to the user, not responding to\n        /// user input, and running in the background.\n        ///\n        /// When the application is in this state, the engine will not call the\n        /// [Window.onBeginFrame] and [Window.onDrawFrame] callbacks.\n        ///\n        /// Android apps in this state should assume that they may enter the\n        /// [suspending] state at any time.\n        paused,\n\n        /// The application will be suspended momentarily.\n        ///\n        /// When the application is in this state, the engine will not call the\n        /// [Window.onBeginFrame] and [Window.onDrawFrame] callbacks.\n        ///\n        /// On iOS, this state is currently unused.\n        suspending,\n    }\n\n    /// A representation of distances for each of the four edges of a rectangle,\n    /// used to encode the view insets and padding that applications should place\n    /// around their user interface, as exposed by [Window.viewInsets] and\n    /// [Window.padding]. View insets and padding are preferably read via\n    /// [MediaQuery.of].\n    ///\n    /// For a generic class that represents distances around a rectangle, see the\n    /// [EdgeInsets] class.\n    ///\n    /// See also:\n    ///\n    ///  * [WidgetsBindingObserver], for a widgets layer mechanism to receive\n    ///    notifications when the padding changes.\n    ///  * [MediaQuery.of], for the preferred mechanism for accessing these values.\n    ///  * [Scaffold], which automatically applies the padding in material design\n    ///    applications.\n    public class WindowPadding\n    {\n        public WindowPadding(double left, double top, double right, double bottom)\n        {\n            this.left = left;\n            this.top = top;\n            this.right = right;\n            this.bottom = bottom;\n        }\n\n        /// The distance from the left edge to the first unpadded pixel, in physical pixels.\n        public readonly double left;\n\n        /// The distance from the top edge to the first unpadded pixel, in physical pixels.\n        public readonly double top;\n\n        /// The distance from the right edge to the first unpadded pixel, in physical pixels.\n        public readonly double right;\n\n        /// The distance from the bottom edge to the first unpadded pixel, in physical pixels.\n        public readonly double bottom;\n\n        /// A window padding that has zeros for each edge.\n        public static WindowPadding zero = new WindowPadding(left: 0.0, top: 0.0, right: 0.0, bottom: 0.0);\n\n        public String toString()\n        {\n            return $\"{nameof(WindowPadding)}(left: {left}, top: {top}, right: {right}, bottom: {bottom})\";\n        }\n    }\n\n    /// An identifier used to select a user's language and formatting preferences,\n    /// consisting of a language and a country. This is a subset of locale\n    /// identifiers as defined by BCP 47.\n    ///\n    /// Locales are canonicalized according to the \"preferred value\" entries in the\n    /// [IANA Language Subtag\n    /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry).\n    /// For example, `const Locale('he')` and `const Locale('iw')` are equal and\n    /// both have the [languageCode] `he`, because `iw` is a deprecated language\n    /// subtag that was replaced by the subtag `he`.\n    ///\n    /// See also:\n    ///\n    ///  * [Window.locale], which specifies the system's currently selected\n    ///    [Locale].\n    public class Locale\n    {\n        /// Creates a new Locale object. The first argument is the\n        /// primary language subtag, the second is the region subtag.\n        ///\n        /// For example:\n        ///\n        /// ```dart\n        /// const Locale swissFrench = const Locale('fr', 'CH');\n        /// const Locale canadianFrench = const Locale('fr', 'CA');\n        /// ```\n        ///\n        /// The primary language subtag must not be null. The region subtag is\n        /// optional.\n        ///\n        /// The values are _case sensitive_, and should match the case of the relevant\n        /// subtags in the [IANA Language Subtag\n        /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry).\n        /// Typically this means the primary language subtag should be lowercase and\n        /// the region subtag should be uppercase.\n        public Locale(string _languageCode, string _countryCode = \"\")\n        {\n            this._languageCode = _languageCode;\n            this._countryCode = _countryCode;\n            // assert(_languageCode != null);\n        }\n\n        /// Empty locale constant. This is an invalid locale.\n        public static Locale none = new Locale(\"\", \"\");\n\n        /// The primary language subtag for the locale.\n        ///\n        /// This must not be null.\n        ///\n        /// This is expected to be string registered in the [IANA Language Subtag\n        /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry)\n        /// with the type \"language\". The string specified must match the case of the\n        /// string in the registry.\n        ///\n        /// Language subtags that are deprecated in the registry and have a preferred\n        /// code are changed to their preferred code. For example, `const\n        /// Locale('he')` and `const Locale('iw')` are equal, and both have the\n        /// [languageCode] `he`, because `iw` is a deprecated language subtag that was\n        /// replaced by the subtag `he`.\n        public String languageCode => _canonicalizeLanguageCode(_languageCode);\n        readonly String _languageCode;\n\n        static String _canonicalizeLanguageCode(String languageCode)\n        {\n            // This switch statement is generated by //flutter/tools/gen_locale.dart\n            // Mappings generated for language subtag registry as of 2018-08-08.\n            switch (languageCode)\n            {\n                case \"in\": return \"id\"; // Indonesian; deprecated 1989-01-01\n                case \"iw\": return \"he\"; // Hebrew; deprecated 1989-01-01\n                case \"ji\": return \"yi\"; // Yiddish; deprecated 1989-01-01\n                case \"jw\": return \"jv\"; // Javanese; deprecated 2001-08-13\n                case \"mo\": return \"ro\"; // Moldavian, Moldovan; deprecated 2008-11-22\n                case \"aam\": return \"aas\"; // Aramanik; deprecated 2015-02-12\n                case \"adp\": return \"dz\"; // Adap; deprecated 2015-02-12\n                case \"aue\": return \"ktz\"; // =/Kx\"au//\"ein; deprecated 2015-02-12\n                case \"ayx\": return \"nun\"; // Ayi (China); deprecated 2011-08-16\n                case \"bgm\": return \"bcg\"; // Baga Mboteni; deprecated 2016-05-30\n                case \"bjd\": return \"drl\"; // Bandjigali; deprecated 2012-08-12\n                case \"ccq\": return \"rki\"; // Chaungtha; deprecated 2012-08-12\n                case \"cjr\": return \"mom\"; // Chorotega; deprecated 2010-03-11\n                case \"cka\": return \"cmr\"; // Khumi Awa Chin; deprecated 2012-08-12\n                case \"cmk\": return \"xch\"; // Chimakum; deprecated 2010-03-11\n                case \"coy\": return \"pij\"; // Coyaima; deprecated 2016-05-30\n                case \"cqu\": return \"quh\"; // Chilean Quechua; deprecated 2016-05-30\n                case \"drh\": return \"khk\"; // Darkhat; deprecated 2010-03-11\n                case \"drw\": return \"prs\"; // Darwazi; deprecated 2010-03-11\n                case \"gav\": return \"dev\"; // Gabutamon; deprecated 2010-03-11\n                case \"gfx\": return \"vaj\"; // Mangetti Dune !Xung; deprecated 2015-02-12\n                case \"ggn\": return \"gvr\"; // Eastern Gurung; deprecated 2016-05-30\n                case \"gti\": return \"nyc\"; // Gbati-ri; deprecated 2015-02-12\n                case \"guv\": return \"duz\"; // Gey; deprecated 2016-05-30\n                case \"hrr\": return \"jal\"; // Horuru; deprecated 2012-08-12\n                case \"ibi\": return \"opa\"; // Ibilo; deprecated 2012-08-12\n                case \"ilw\": return \"gal\"; // Talur; deprecated 2013-09-10\n                case \"jeg\": return \"oyb\"; // Jeng; deprecated 2017-02-23\n                case \"kgc\": return \"tdf\"; // Kasseng; deprecated 2016-05-30\n                case \"kgh\": return \"kml\"; // Upper Tanudan Kalinga; deprecated 2012-08-12\n                case \"koj\": return \"kwv\"; // Sara Dunjo; deprecated 2015-02-12\n                case \"krm\": return \"bmf\"; // Krim; deprecated 2017-02-23\n                case \"ktr\": return \"dtp\"; // Kota Marudu Tinagas; deprecated 2016-05-30\n                case \"kvs\": return \"gdj\"; // Kunggara; deprecated 2016-05-30\n                case \"kwq\": return \"yam\"; // Kwak; deprecated 2015-02-12\n                case \"kxe\": return \"tvd\"; // Kakihum; deprecated 2015-02-12\n                case \"kzj\": return \"dtp\"; // Coastal Kadazan; deprecated 2016-05-30\n                case \"kzt\": return \"dtp\"; // Tambunan Dusun; deprecated 2016-05-30\n                case \"lii\": return \"raq\"; // Lingkhim; deprecated 2015-02-12\n                case \"lmm\": return \"rmx\"; // Lamam; deprecated 2014-02-28\n                case \"meg\": return \"cir\"; // Mea; deprecated 2013-09-10\n                case \"mst\": return \"mry\"; // Cataelano Mandaya; deprecated 2010-03-11\n                case \"mwj\": return \"vaj\"; // Maligo; deprecated 2015-02-12\n                case \"myt\": return \"mry\"; // Sangab Mandaya; deprecated 2010-03-11\n                case \"nad\": return \"xny\"; // Nijadali; deprecated 2016-05-30\n                case \"ncp\": return \"kdz\"; // Ndaktup; deprecated 2018-03-08\n                case \"nnx\": return \"ngv\"; // Ngong; deprecated 2015-02-12\n                case \"nts\": return \"pij\"; // Natagaimas; deprecated 2016-05-30\n                case \"oun\": return \"vaj\"; // !O!ung; deprecated 2015-02-12\n                case \"pcr\": return \"adx\"; // Panang; deprecated 2013-09-10\n                case \"pmc\": return \"huw\"; // Palumata; deprecated 2016-05-30\n                case \"pmu\": return \"phr\"; // Mirpur Panjabi; deprecated 2015-02-12\n                case \"ppa\": return \"bfy\"; // Pao; deprecated 2016-05-30\n                case \"ppr\": return \"lcq\"; // Piru; deprecated 2013-09-10\n                case \"pry\": return \"prt\"; // Pray 3; deprecated 2016-05-30\n                case \"puz\": return \"pub\"; // Purum Naga; deprecated 2014-02-28\n                case \"sca\": return \"hle\"; // Sansu; deprecated 2012-08-12\n                case \"skk\": return \"oyb\"; // Sok; deprecated 2017-02-23\n                case \"tdu\": return \"dtp\"; // Tempasuk Dusun; deprecated 2016-05-30\n                case \"thc\": return \"tpo\"; // Tai Hang Tong; deprecated 2016-05-30\n                case \"thx\": return \"oyb\"; // The; deprecated 2015-02-12\n                case \"tie\": return \"ras\"; // Tingal; deprecated 2011-08-16\n                case \"tkk\": return \"twm\"; // Takpa; deprecated 2011-08-16\n                case \"tlw\": return \"weo\"; // South Wemale; deprecated 2012-08-12\n                case \"tmp\": return \"tyj\"; // Tai Mène; deprecated 2016-05-30\n                case \"tne\": return \"kak\"; // Tinoc Kallahan; deprecated 2016-05-30\n                case \"tnf\": return \"prs\"; // Tangshewi; deprecated 2010-03-11\n                case \"tsf\": return \"taj\"; // Southwestern Tamang; deprecated 2015-02-12\n                case \"uok\": return \"ema\"; // Uokha; deprecated 2015-02-12\n                case \"xba\": return \"cax\"; // Kamba (Brazil); deprecated 2016-05-30\n                case \"xia\": return \"acn\"; // Xiandao; deprecated 2013-09-10\n                case \"xkh\": return \"waw\"; // Karahawyana; deprecated 2016-05-30\n                case \"xsj\": return \"suj\"; // Subi; deprecated 2015-02-12\n                case \"ybd\": return \"rki\"; // Yangbye; deprecated 2012-08-12\n                case \"yma\": return \"lrr\"; // Yamphe; deprecated 2012-08-12\n                case \"ymt\": return \"mtm\"; // Mator-Taygi-Karagas; deprecated 2015-02-12\n                case \"yos\": return \"zom\"; // Yos; deprecated 2013-09-10\n                case \"yuu\": return \"yug\"; // Yugh; deprecated 2014-02-28\n                default: return languageCode;\n            }\n        }\n\n        /// The region subtag for the locale.\n        ///\n        /// This can be null.\n        ///\n        /// This is expected to be string registered in the [IANA Language Subtag\n        /// Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry)\n        /// with the type \"region\". The string specified must match the case of the\n        /// string in the registry.\n        ///\n        /// Region subtags that are deprecated in the registry and have a preferred\n        /// code are changed to their preferred code. For example, `const Locale('de',\n        /// 'DE')` and `const Locale('de', 'DD')` are equal, and both have the\n        /// [countryCode] `DE`, because `DD` is a deprecated language subtag that was\n        /// replaced by the subtag `DE`.\n        String countryCode => _canonicalizeRegionCode(_countryCode);\n        readonly String _countryCode;\n\n        static String _canonicalizeRegionCode(String regionCode)\n        {\n            // This switch statement is generated by //flutter/tools/gen_locale.dart\n            // Mappings generated for language subtag registry as of 2018-08-08.\n            switch (regionCode)\n            {\n                case \"BU\": return \"MM\"; // Burma; deprecated 1989-12-05\n                case \"DD\": return \"DE\"; // German Democratic Republic; deprecated 1990-10-30\n                case \"FX\": return \"FR\"; // Metropolitan France; deprecated 1997-07-14\n                case \"TP\": return \"TL\"; // East Timor; deprecated 2002-05-20\n                case \"YD\": return \"YE\"; // Democratic Yemen; deprecated 1990-08-14\n                case \"ZR\": return \"CD\"; // Zaire; deprecated 1997-07-14\n                default: return regionCode;\n            }\n        }\n\n\n        //public static bool operator ==(Locale first, Locale second)\n        //{       \n        //\n        //    if (first.Equals(second))\n        //        return true;\n        //    if (!(second is Locale))\n        //        return false;\n        //    Locale typedOther = second;\n        //    return second.languageCode == first.languageCode\n        //        && second.countryCode == first.countryCode;\n        //}\n\n        //public static bool operator !=(Locale first, Locale second) => !(first == second);\n\n        public int hashCode\n        {\n            get\n            {\n                int result = 373;\n                result = 37 * result + languageCode.GetHashCode();\n                if (_countryCode != null)\n                    result = 37 * result + countryCode.GetHashCode();\n                return result;\n            }\n        }\n\n        public String toString()\n        {\n            if (_countryCode == null)\n                return languageCode;\n            return $\"{languageCode}_{countryCode}\";\n        }\n    }\n\n    /// The most basic interface to the host operating system's user interface.\n    ///\n    /// There is a single Window instance in the system, which you can\n    /// obtain from the [window] property.\n    public class Window: Engine.Window.NativeWindow\n    {\n        static Window _instance;\n        public static Window Instance => _instance ?? (_instance = new Window());\n\n\n        private Window() { }\n\n        /// The number of device pixels for each logical pixel. This number might not\n        /// be a power of two. Indeed, it might not even be an integer. For example,\n        /// the Nexus 6 has a device pixel ratio of 3.5.\n        ///\n        /// Device pixels are also referred to as physical pixels. Logical pixels are\n        /// also referred to as device-independent or resolution-independent pixels.\n        ///\n        /// By definition, there are roughly 38 logical pixels per centimeter, or\n        /// about 96 logical pixels per inch, of the physical display. The value\n        /// returned by [devicePixelRatio] is ultimately obtained either from the\n        /// hardware itself, the device drivers, or a hard-coded value stored in the\n        /// operating system or firmware, and may be inaccurate, sometimes by a\n        /// significant margin.\n        ///\n        /// The Flutter framework operates in logical pixels, so it is rarely\n        /// necessary to directly deal with this property.\n        ///\n        /// When this changes, [onMetricsChanged] is called.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        public double devicePixelRatio { get; set; } = 1.0;\n\n        /// The dimensions of the rectangle into which the application will be drawn,\n        /// in physical pixels.\n        ///\n        /// When this changes, [onMetricsChanged] is called.\n        ///\n        /// At startup, the size of the application window may not be known before Dart\n        /// code runs. If this value is observed early in the application lifecycle,\n        /// it may report [Size.zero].\n        ///\n        /// This value does not take into account any on-screen keyboards or other\n        /// system UI. The [padding] and [viewInsets] properties provide a view into\n        /// how much of each side of the application may be obscured by system UI.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        public Size physicalSize { get; set; } = Size.zero;\n\n        /// The number of physical pixels on each side of the display rectangle into\n        /// which the application can render, but over which the operating system\n        /// will likely place system UI, such as the keyboard, that fully obscures\n        /// any content.\n        ///\n        /// When this changes, [onMetricsChanged] is called.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        ///  * [MediaQuery.of], a simpler mechanism for the same.\n        ///  * [Scaffold], which automatically applies the view insets in material\n        ///    design applications.\n        public WindowPadding viewInsets { get; set; } = WindowPadding.zero;\n\n        /// The number of physical pixels on each side of the display rectangle into\n        /// which the application can render, but which may be partially obscured by\n        /// system UI (such as the system notification area), or or physical\n        /// intrusions in the display (e.g. overscan regions on television screens or\n        /// phone sensor housings).\n        ///\n        /// When this changes, [onMetricsChanged] is called.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        ///  * [MediaQuery.of], a simpler mechanism for the same.\n        ///  * [Scaffold], which automatically applies the padding in material design\n        ///    applications.\n        public WindowPadding padding { get; set; } = WindowPadding.zero;\n\n        /// A callback that is invoked whenever the [devicePixelRatio],\n        /// [physicalSize], [padding], or [viewInsets] values change, for example\n        /// when the device is rotated or when the application is resized (e.g. when\n        /// showing applications side-by-side on Android).\n        ///\n        /// The engine invokes this callback in the same zone in which the callback\n        /// was set.\n        ///\n        /// The framework registers with this callback and updates the layout\n        /// appropriately.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    register for notifications when this is called.\n        ///  * [MediaQuery.of], a simpler mechanism for the same.\n        public VoidCallback onMetricsChanged\n        {\n            get { return _onMetricsChanged; }\n            set\n            {\n                _onMetricsChanged = value;\n                _onMetricsChangedZone = Zone.current;\n            }\n        }\n        VoidCallback _onMetricsChanged;\n        public Zone _onMetricsChangedZone;\n\n\n        /// The system-reported default locale of the device.\n        ///\n        /// This establishes the language and formatting conventions that application\n        /// should, if possible, use to render their user interface.\n        ///\n        /// This is the first locale selected by the user and is the user's\n        /// primary locale (the locale the device UI is displayed in)\n        ///\n        /// This is equivalent to `locales.first` and will provide an empty non-null locale\n        /// if the [locales] list has not been set or is empty.\n        public Locale locale\n        {\n            get\n            {\n                if (locales != null && locales.Count > 0)\n                {\n                    return locales.First();\n                }\n                return Locale.none;\n            }\n        }\n\n        /// The full system-reported supported locales of the device.\n        ///\n        /// This establishes the language and formatting conventions that application\n        /// should, if possible, use to render their user interface.\n        ///\n        /// The list is ordered in order of priority, with lower-indexed locales being\n        /// preferred over higher-indexed ones. The first element is the primary [locale].\n        ///\n        /// The [onLocaleChanged] callback is called whenever this value changes.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        public List<Locale> locales { get; set;  }\n\n        /// A callback that is invoked whenever [locale] changes value.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this callback is invoked.\n        public VoidCallback onLocaleChanged\n        {\n            get { return _onLocaleChanged; }\n            set\n            {\n                _onLocaleChanged = value;\n                _onLocaleChangedZone = Zone.current;\n            }\n        }\n        VoidCallback _onLocaleChanged;\n        public Zone _onLocaleChangedZone;\n\n        /// The system-reported text scale.\n        ///\n        /// This establishes the text scaling factor to use when rendering text,\n        /// according to the user's platform preferences.\n        ///\n        /// The [onTextScaleFactorChanged] callback is called whenever this value\n        /// changes.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this value changes.\n        public double textScaleFactor { get; set; } = 1.0;\n\n        /// The setting indicating whether time should always be shown in the 24-hour\n        /// format.\n        ///\n        /// This option is used by [showTimePicker].\n        public bool alwaysUse24HourFormat { get; set; } = false;\n\n        /// A callback that is invoked whenever [textScaleFactor] changes value.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        ///\n        /// See also:\n        ///\n        ///  * [WidgetsBindingObserver], for a mechanism at the widgets layer to\n        ///    observe when this callback is invoked.\n        public VoidCallback onTextScaleFactorChanged\n        {\n            get { return _onTextScaleFactorChanged; }\n            set\n            {\n                _onTextScaleFactorChanged = value;\n                _onTextScaleFactorChangedZone = Zone.current;\n            }\n        }\n        VoidCallback _onTextScaleFactorChanged;\n        public Zone _onTextScaleFactorChangedZone;\n\n        /// A callback that is invoked to notify the application that it is an\n        /// appropriate time to provide a scene using the [SceneBuilder] API and the\n        /// [render] method. When possible, this is driven by the hardware VSync\n        /// signal. This is only called if [scheduleFrame] has been called since the\n        /// last time this callback was invoked.\n        ///\n        /// The [onDrawFrame] callback is invoked immediately after [onBeginFrame],\n        /// after draining any microtasks (e.g. completions of any [Future]s) queued\n        /// by the [onBeginFrame] handler.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        ///\n        /// See also:\n        ///\n        ///  * [SchedulerBinding], the Flutter framework class which manages the\n        ///    scheduling of frames.\n        ///  * [RendererBinding], the Flutter framework class which manages layout and\n        ///    painting.\n        public FrameCallback onBeginFrame\n        {\n            get { return _onBeginFrame; }\n            set\n            {\n                _onBeginFrame = value;\n                _onBeginFrameZone = Zone.current;\n            }\n        }\n        FrameCallback _onBeginFrame;\n        public Zone _onBeginFrameZone;\n\n        /// A callback that is invoked for each frame after [onBeginFrame] has\n        /// completed and after the microtask queue has been drained. This can be\n        /// used to implement a second phase of frame rendering that happens\n        /// after any deferred work queued by the [onBeginFrame] phase.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        ///\n        /// See also:\n        ///\n        ///  * [SchedulerBinding], the Flutter framework class which manages the\n        ///    scheduling of frames.\n        ///  * [RendererBinding], the Flutter framework class which manages layout and\n        ///    painting.\n        public VoidCallback onDrawFrame\n        {\n            get { return _onDrawFrame; }\n            set\n            {\n                _onDrawFrame = value;\n                _onDrawFrameZone = Zone.current;\n            }\n        }\n        VoidCallback _onDrawFrame;\n        public Zone _onDrawFrameZone;\n\n        /// A callback that is invoked when pointer data is available.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        ///\n        /// See also:\n        ///\n        ///  * [GestureBinding], the Flutter framework class which manages pointer\n        ///    events.\n        public PointerDataPacketCallback onPointerDataPacket\n        {\n            get { return _onPointerDataPacket; }\n            set\n            {\n                _onPointerDataPacket = value;\n                _onPointerDataPacketZone = Zone.current;\n            }\n        }\n        PointerDataPacketCallback _onPointerDataPacket;\n        public Zone _onPointerDataPacketZone;\n\n        /// The route or path that the embedder requested when the application was\n        /// launched.\n        ///\n        /// This will be the string \"`/`\" if no particular route was requested.\n        ///\n        /// ## Android\n        ///\n        /// On Android, calling\n        /// [`FlutterView.setInitialRoute`](/javadoc/io/flutter/view/FlutterView.html#setInitialRoute-java.lang.String-)\n        /// will set this value. The value must be set sufficiently early, i.e. before\n        /// the [runApp] call is executed in Dart, for this to have any effect on the\n        /// framework. The `createFlutterView` method in your `FlutterActivity`\n        /// subclass is a suitable time to set the value. The application's\n        /// `AndroidManifest.xml` file must also be updated to have a suitable\n        /// [`<intent-filter>`](https://developer.android.com/guide/topics/manifest/intent-filter-element.html).\n        ///\n        /// ## iOS\n        ///\n        /// On iOS, calling\n        /// [`FlutterViewController.setInitialRoute`](/objcdoc/Classes/FlutterViewController.html#/c:objc%28cs%29FlutterViewController%28im%29setInitialRoute:)\n        /// will set this value. The value must be set sufficiently early, i.e. before\n        /// the [runApp] call is executed in Dart, for this to have any effect on the\n        /// framework. The `application:didFinishLaunchingWithOptions:` method is a\n        /// suitable time to set this value.\n        ///\n        /// See also:\n        ///\n        ///  * [Navigator], a widget that handles routing.\n        ///  * [SystemChannels.navigation], which handles subsequent navigation\n        ///    requests from the embedder.\n        public String defaultRouteName => _defaultRouteName();\n        String _defaultRouteName()\n        {\n            // native 'Window_defaultRouteName';\n            return string.Empty; // Tmp to resolve build\n        }\n\n\n        /// Requests that, at the next appropriate opportunity, the [onBeginFrame]\n        /// and [onDrawFrame] callbacks be invoked.\n        ///\n        /// See also:\n        ///\n        ///  * [SchedulerBinding], the Flutter framework class which manages the\n        ///    scheduling of frames.\n        public void scheduleFrame()\n        {\n            // native 'Window_scheduleFrame';\n        }\n\n        /// Updates the application's rendering on the GPU with the newly provided\n        /// [Scene]. This function must be called within the scope of the\n        /// [onBeginFrame] or [onDrawFrame] callbacks being invoked. If this function\n        /// is called a second time during a single [onBeginFrame]/[onDrawFrame]\n        /// callback sequence or called outside the scope of those callbacks, the call\n        /// will be ignored.\n        ///\n        /// To record graphical operations, first create a [PictureRecorder], then\n        /// construct a [Canvas], passing that [PictureRecorder] to its constructor.\n        /// After issuing all the graphical operations, call the\n        /// [PictureRecorder.endRecording] function on the [PictureRecorder] to obtain\n        /// the final [Picture] that represents the issued graphical operations.\n        ///\n        /// Next, create a [SceneBuilder], and add the [Picture] to it using\n        /// [SceneBuilder.addPicture]. With the [SceneBuilder.build] method you can\n        /// then obtain a [Scene] object, which you can display to the user via this\n        /// [render] function.\n        ///\n        /// See also:\n        ///\n        ///  * [SchedulerBinding], the Flutter framework class which manages the\n        ///    scheduling of frames.\n        ///  * [RendererBinding], the Flutter framework class which manages layout and\n        ///    painting.\n        public void render(Scene scene)\n        {\n            this.Render(scene);\n            // [DONE] native 'Window_render';\n        }\n\n        /// Whether the user has requested that [updateSemantics] be called when\n        /// the semantic contents of window changes.\n        ///\n        /// The [onSemanticsEnabledChanged] callback is called whenever this value\n        /// changes.\n        public bool semanticsEnabled { get; set; } = false;\n\n        /// A callback that is invoked when the value of [semanticsEnabled] changes.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        public VoidCallback onSemanticsEnabledChanged\n        {\n            get { return _onSemanticsEnabledChanged; }\n            set\n            {\n                _onSemanticsEnabledChanged = value;\n                _onSemanticsEnabledChangedZone = Zone.current;\n            }\n        }\n        VoidCallback _onSemanticsEnabledChanged;\n        public Zone _onSemanticsEnabledChangedZone;\n\n        /// A callback that is invoked whenever the user requests an action to be\n        /// performed.\n        ///\n        /// This callback is used when the user expresses the action they wish to\n        /// perform based on the semantics supplied by [updateSemantics].\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        public SemanticsActionCallback onSemanticsAction\n        {\n            get { return _onSemanticsAction; }\n            set\n            {\n                _onSemanticsAction = value;\n                _onSemanticsActionZone = Zone.current;\n            }\n        }\n        SemanticsActionCallback _onSemanticsAction;\n        public Zone _onSemanticsActionZone;\n\n        /// Additional accessibility features that may be enabled by the platform.\n        public AccessibilityFeatures accessibilityFeatures { get; set; }\n\n        /// A callback that is invoked when the value of [accessibilityFlags] changes.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        public VoidCallback onAccessibilityFeaturesChanged\n        {\n            get { return _onAccessibilityFeaturesChanged; }\n            set\n            {\n                _onAccessibilityFeaturesChanged = value;\n                _onAccessibilityFlagsChangedZone = Zone.current;\n            }\n        }\n        VoidCallback _onAccessibilityFeaturesChanged;\n        public Zone _onAccessibilityFlagsChangedZone;\n\n        /// Change the retained semantics data about this window.\n        ///\n        /// If [semanticsEnabled] is true, the user has requested that this funciton\n        /// be called whenever the semantic content of this window changes.\n        ///\n        /// In either case, this function disposes the given update, which means the\n        /// semantics update cannot be used further.\n        public void updateSemantics(SemanticsUpdate update)\n        {\n            // native 'Window_updateSemantics';\n        }\n\n        /// Set the debug name associated with this window's root isolate.\n        ///\n        /// Normally debug names are automatically generated from the Dart port, entry\n        /// point, and source file. For example: `main.dart$main-1234`.\n        ///\n        /// This can be combined with flutter tools `--isolate-filter` flag to debug\n        /// specific root isolates. For example: `flutter attach --isolate-filter=[name]`.\n        /// Note that this does not rename any child isolates of the root.\n        public void setIsolateDebugName(String name)\n        {\n            // native 'Window_setIsolateDebugName';\n        }\n\n        /// Sends a message to a platform-specific plugin.\n        ///\n        /// The `name` parameter determines which plugin receives the message. The\n        /// `data` parameter contains the message payload and is typically UTF-8\n        /// encoded JSON but can be arbitrary data. If the plugin replies to the\n        /// message, `callback` will be called with the response.\n        ///\n        /// The framework invokes [callback] in the same zone in which this method\n        /// was called.\n        public void sendPlatformMessage(String name,\n                                 ByteData data,\n                                 PlatformMessageResponseCallback callback)\n        {\n            String error =\n                _sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);\n            if (error != null)\n                throw new Exception(error);\n        }\n        String _sendPlatformMessage(String name,\n                                    PlatformMessageResponseCallback callback,\n                                    ByteData data)\n        {\n            // native 'Window_sendPlatformMessage';\n            return string.Empty; // Tmp to resolve build\n        }\n\n        /// Called whenever this window receives a message from a platform-specific\n        /// plugin.\n        ///\n        /// The `name` parameter determines which plugin sent the message. The `data`\n        /// parameter is the payload and is typically UTF-8 encoded JSON but can be\n        /// arbitrary data.\n        ///\n        /// Message handlers must call the function given in the `callback` parameter.\n        /// If the handler does not need to respond, the handler should pass null to\n        /// the callback.\n        ///\n        /// The framework invokes this callback in the same zone in which the\n        /// callback was set.\n        public PlatformMessageCallback onPlatformMessage\n        {\n            get { return _onPlatformMessage; }\n            set\n            {\n                _onPlatformMessage = value;\n                _onPlatformMessageZone = Zone.current;\n            }\n        }\n        PlatformMessageCallback _onPlatformMessage;\n        public Zone _onPlatformMessageZone;\n\n        /// Called by [_dispatchPlatformMessage].\n        public void _respondToPlatformMessage(int responseId, ByteData data)\n        {\n            // native 'Window_respondToPlatformMessage';\n        }\n        /// Wraps the given [callback] in another callback that ensures that the\n        /// original callback is called in the zone it was registered in.\n        static PlatformMessageResponseCallback _zonedPlatformMessageResponseCallback(PlatformMessageResponseCallback callback)\n        {\n            if (callback == null)\n                return null;\n\n            // Store the zone in which the callback is being registered.\n            Zone registrationZone = Zone.current;\n\n            return (data) => registrationZone.runUnaryGuarded(callback, data);\n\n        }\n    }\n\n    /// Additional accessibility features that may be enabled by the platform.\n    ///\n    /// It is not possible to enable these settings from Flutter, instead they are\n    /// used by the platform to indicate that additional accessibility features are\n    /// enabled.\n    public class AccessibilityFeatures\n    {\n        public AccessibilityFeatures(int _index) { this._index = _index; }\n\n        const int _kAccessibleNavigation = 1 << 0;\n        const int _kInvertColorsIndex = 1 << 1;\n        const int _kDisableAnimationsIndex = 1 << 2;\n        const int _kBoldTextIndex = 1 << 3;\n        const int _kReduceMotionIndex = 1 << 4;\n\n        // A bitfield which represents each enabled feature.\n        readonly int _index;\n\n        /// Whether there is a running accessibility service which is changing the\n        /// interaction model of the device.\n        ///\n        /// For example, TalkBack on Android and VoiceOver on iOS enable this flag.\n        public bool accessibleNavigation => (_kAccessibleNavigation & _index) != 0;\n\n        /// The platform is inverting the colors of the application.\n        public bool invertColors => (_kInvertColorsIndex & _index) != 0;\n\n        /// The platform is requesting that animations be disabled or simplified.\n        public bool disableAnimations => (_kDisableAnimationsIndex & _index) != 0;\n\n        /// The platform is requesting that text be rendered at a bold font weight.\n        ///\n        /// Only supported on iOS.\n        public bool boldText => (_kBoldTextIndex & _index) != 0;\n\n        /// The platform is requesting that certain animations be simplified and\n        /// parallax effects removed.\n        ///\n        /// Only supported on iOS.\n        public bool reduceMotion => (_kReduceMotionIndex & _index) != 0;\n\n        public String toString()\n        {\n            List<String> features = new List<String>();\n            if (accessibleNavigation)\n                features.Add(\"accessibleNavigation\");\n            if (invertColors)\n                features.Add(\"invertColors\");\n            if (disableAnimations)\n                features.Add(\"disableAnimations\");\n            if (boldText)\n                features.Add(\"boldText\");\n            if (reduceMotion)\n                features.Add(\"reduceMotion\");\n            return $\"AccessibilityFeatures{features}\";\n        }\n\n        public static bool operator ==(AccessibilityFeatures first, AccessibilityFeatures other)\n        {\n            if (other.GetType() != first.GetType())\n                return false;\n            AccessibilityFeatures typedOther = other;\n            return first._index == typedOther._index;\n        }\n\n        public static bool operator !=(AccessibilityFeatures first, AccessibilityFeatures other) => !(first == other);\n\n        public int hashCode => _index.GetHashCode();\n    }\n\n    /// The [Window] singleton. This object exposes the size of the display, the\n    /// core scheduler API, the input event callback, the graphics drawing API, and\n    /// other such core services.\n    //readonly Window window = new Window();\n    // Do Window.Instance instead\n}\n"
  },
  {
    "path": "FlutterBindingSample/App.xaml",
    "content": "﻿<Application\n    x:Class=\"FlutterBindingSample.App\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:FlutterBindingSample\">\n\n</Application>\n"
  },
  {
    "path": "FlutterBindingSample/App.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices.WindowsRuntime;\nusing Windows.ApplicationModel;\nusing Windows.ApplicationModel.Activation;\nusing Windows.Foundation;\nusing Windows.Foundation.Collections;\nusing Windows.UI.Xaml;\nusing Windows.UI.Xaml.Controls;\nusing Windows.UI.Xaml.Controls.Primitives;\nusing Windows.UI.Xaml.Data;\nusing Windows.UI.Xaml.Input;\nusing Windows.UI.Xaml.Media;\nusing Windows.UI.Xaml.Navigation;\n\nnamespace FlutterBindingSample\n{\n    /// <summary>\n    /// Provides application-specific behavior to supplement the default Application class.\n    /// </summary>\n    sealed partial class App : Application\n    {\n        /// <summary>\n        /// Initializes the singleton application object.  This is the first line of authored code\n        /// executed, and as such is the logical equivalent of main() or WinMain().\n        /// </summary>\n        public App()\n        {\n            this.InitializeComponent();\n            this.Suspending += OnSuspending;\n        }\n\n        /// <summary>\n        /// Invoked when the application is launched normally by the end user.  Other entry points\n        /// will be used such as when the application is launched to open a specific file.\n        /// </summary>\n        /// <param name=\"e\">Details about the launch request and process.</param>\n        protected override void OnLaunched(LaunchActivatedEventArgs e)\n        {\n            Frame rootFrame = Window.Current.Content as Frame;\n\n            // Do not repeat app initialization when the Window already has content,\n            // just ensure that the window is active\n            if (rootFrame == null)\n            {\n                // Create a Frame to act as the navigation context and navigate to the first page\n                rootFrame = new Frame();\n\n                rootFrame.NavigationFailed += OnNavigationFailed;\n\n                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)\n                {\n                    //TODO: Load state from previously suspended application\n                }\n\n                // Place the frame in the current Window\n                Window.Current.Content = rootFrame;\n            }\n\n            if (e.PrelaunchActivated == false)\n            {\n                if (rootFrame.Content == null)\n                {\n                    // When the navigation stack isn't restored navigate to the first page,\n                    // configuring the new page by passing required information as a navigation\n                    // parameter\n                    rootFrame.Navigate(typeof(MainPage), e.Arguments);\n                }\n                // Ensure the current window is active\n                Window.Current.Activate();\n            }\n\n            var appView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();\n            appView.Title = \"Xamarin.Flutter in UWP\";\n        }\n\n        /// <summary>\n        /// Invoked when Navigation to a certain page fails\n        /// </summary>\n        /// <param name=\"sender\">The Frame which failed navigation</param>\n        /// <param name=\"e\">Details about the navigation failure</param>\n        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)\n        {\n            throw new Exception(\"Failed to load Page \" + e.SourcePageType.FullName);\n        }\n\n        /// <summary>\n        /// Invoked when application execution is being suspended.  Application state is saved\n        /// without knowing whether the application will be terminated or resumed with the contents\n        /// of memory still intact.\n        /// </summary>\n        /// <param name=\"sender\">The source of the suspend request.</param>\n        /// <param name=\"e\">Details about the suspend request.</param>\n        private void OnSuspending(object sender, SuspendingEventArgs e)\n        {\n            var deferral = e.SuspendingOperation.GetDeferral();\n            //TODO: Save application state and stop any background activity\n            deferral.Complete();\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBindingSample/FlutterBindingSample.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x86</Platform>\n    <ProjectGuid>{2AFB0021-0EE7-4F30-9598-22E269F355CA}</ProjectGuid>\n    <OutputType>AppContainerExe</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>FlutterBindingSample</RootNamespace>\n    <AssemblyName>FlutterBindingSample</AssemblyName>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>\n    <TargetPlatformVersion Condition=\" '$(TargetPlatformVersion)' == '' \">10.0.17763.0</TargetPlatformVersion>\n    <TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>\n    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>\n    <PackageCertificateKeyFile>FlutterBindingSample_TemporaryKey.pfx</PackageCertificateKeyFile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\n  </PropertyGroup>\n  <PropertyGroup>\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"App.xaml.cs\">\n      <DependentUpon>App.xaml</DependentUpon>\n    </Compile>\n    <Compile Include=\"MainPage.xaml.cs\">\n      <DependentUpon>MainPage.xaml</DependentUpon>\n    </Compile>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <AppxManifest Include=\"Package.appxmanifest\">\n      <SubType>Designer</SubType>\n    </AppxManifest>\n    <None Include=\"FlutterBindingSample_TemporaryKey.pfx\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"Properties\\Default.rd.xml\" />\n    <Content Include=\"Assets\\LockScreenLogo.scale-200.png\" />\n    <Content Include=\"Assets\\SplashScreen.scale-200.png\" />\n    <Content Include=\"Assets\\Square150x150Logo.scale-200.png\" />\n    <Content Include=\"Assets\\Square44x44Logo.scale-200.png\" />\n    <Content Include=\"Assets\\Square44x44Logo.targetsize-24_altform-unplated.png\" />\n    <Content Include=\"Assets\\StoreLogo.png\" />\n    <Content Include=\"Assets\\Wide310x150Logo.scale-200.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ApplicationDefinition Include=\"App.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </ApplicationDefinition>\n    <Page Include=\"MainPage.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NETCore.UniversalWindowsPlatform\">\n      <Version>6.1.9</Version>\n    </PackageReference>\n    <PackageReference Include=\"SkiaSharp\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n    <PackageReference Include=\"SkiaSharp.Views\">\n      <Version>1.60.3</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\FlutterBinding\\FlutterBinding.csproj\">\n      <Project>{c9313643-3357-4872-9b00-03e2c79ad297}</Project>\n      <Name>FlutterBinding</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\FlutterSDK\\FlutterSDK.csproj\">\n      <Project>{0781218d-0bcf-4528-aa32-a1937572e43b}</Project>\n      <Name>FlutterSDK</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' \">\n    <VisualStudioVersion>14.0</VisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "FlutterBindingSample/MainPage.xaml",
    "content": "﻿<Page\n    x:Class=\"FlutterBindingSample.MainPage\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:FlutterBindingSample\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n    mc:Ignorable=\"d\"\n    xmlns:skia=\"using:SkiaSharp.Views.UWP\">\n    <Grid Background=\"{ThemeResource ApplicationPageBackgroundThemeBrush}\">\n        <skia:SKXamlCanvas x:Name=\"CanvasView\" PaintSurface=\"OnCanvasViewPaintSurface\" />\n    </Grid>\n</Page>\n"
  },
  {
    "path": "FlutterBindingSample/MainPage.xaml.cs",
    "content": "﻿using FlutterBinding.Engine;\nusing FlutterSDK.Widgets.Basic;\nusing FlutterSDK.Widgets.Framework;\nusing FlutterSDK.Widgets.Text;\nusing SkiaSharp.Views.UWP;\nusing Windows.UI.Xaml.Controls;\n\nnamespace FlutterBindingSample\n{\n    /// <summary>\n    /// An empty page that can be used on its own or navigated to within a Frame.\n    /// </summary>\n    public sealed partial class MainPage : Page\n    {\n        public MainPage()\n        {\n            this.InitializeComponent();\n        }\n\n        public class MyApp : StatelessWidget\n        {\n            public override Widget Build(BuildContext context)\n            {\n                return new Center(\n                    child: new Text(\"Hello Xamarin.Flutter!\")\n                  );\n            }\n        }\n\n      \n\n        public void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)\n        {\n            var canvas = e.Surface.Canvas;\n\n            var frame = ((Frame)Windows.UI.Xaml.Window.Current.Content);\n\n            FlutterBinding.UI.Window.Instance.physicalSize = new FlutterBinding.UI.Size(frame.ActualWidth, frame.ActualHeight);\n\n            Engine.Instance.LoadCanvas(e.Surface.Canvas);\n            Engine.Instance.SetSize(frame.ActualWidth, frame.ActualHeight);\n\n            //RunApp(new MyApp());\n        }\n\n\n        public void BeginFrame()\n        {\n            var window = FlutterBinding.UI.Window.Instance;\n\n            double devicePixelRatio = window.devicePixelRatio;\n            var physicalSize = window.physicalSize;\n            var logicalSize = physicalSize / devicePixelRatio;\n\n            var paragraphBuilder = new FlutterBinding.UI.ParagraphBuilder(new FlutterBinding.UI.ParagraphStyle());\n            paragraphBuilder.addText(\"Hello World!\");\n            var paragraph = paragraphBuilder.build();\n\n            paragraph.layout(new FlutterBinding.UI.ParagraphConstraints(width: logicalSize.width));\n\n            var physicalBounds = FlutterBinding.UI.Offset.zero & physicalSize;\n            var recorder = new FlutterBinding.UI.PictureRecorder();\n\n            var canvas = new FlutterBinding.UI.Canvas(recorder, physicalBounds);\n            canvas.scale((float)devicePixelRatio, (float)devicePixelRatio);\n            canvas.drawParagraph(paragraph, new FlutterBinding.UI.Offset(\n                (logicalSize.width - paragraph.maxIntrinsicWidth) / 2.0,\n                (logicalSize.height - paragraph.height) / 2.0\n                ));\n\n            var picture = recorder.endRecording();\n\n            var sceneBuilder = new FlutterBinding.UI.SceneBuilder();\n            sceneBuilder.pushClipRect(physicalBounds);\n            sceneBuilder.addPicture(FlutterBinding.UI.Offset.zero, picture);\n            sceneBuilder.pop();\n\n            var scene = sceneBuilder.build();\n\n            window.render(scene);\n        }\n    }\n}\n"
  },
  {
    "path": "FlutterBindingSample/Package.appxmanifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<Package\n  xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\"\n  xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n  xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\"\n  IgnorableNamespaces=\"uap mp\">\n\n  <Identity\n    Name=\"bc373a6d-c1ac-4b64-aa61-412323aeec30\"\n    Publisher=\"CN=Adam\"\n    Version=\"1.0.0.0\" />\n\n  <mp:PhoneIdentity PhoneProductId=\"bc373a6d-c1ac-4b64-aa61-412323aeec30\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n\n  <Properties>\n    <DisplayName>FlutterBindingSample</DisplayName>\n    <PublisherDisplayName>Adam</PublisherDisplayName>\n    <Logo>Assets\\StoreLogo.png</Logo>\n  </Properties>\n\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n  </Dependencies>\n\n  <Resources>\n    <Resource Language=\"x-generate\"/>\n  </Resources>\n\n  <Applications>\n    <Application Id=\"App\"\n      Executable=\"$targetnametoken$.exe\"\n      EntryPoint=\"FlutterBindingSample.App\">\n      <uap:VisualElements\n        DisplayName=\"FlutterBindingSample\"\n        Square150x150Logo=\"Assets\\Square150x150Logo.png\"\n        Square44x44Logo=\"Assets\\Square44x44Logo.png\"\n        Description=\"FlutterBindingSample\"\n        BackgroundColor=\"transparent\">\n        <uap:DefaultTile Wide310x150Logo=\"Assets\\Wide310x150Logo.png\"/>\n        <uap:SplashScreen Image=\"Assets\\SplashScreen.png\" />\n      </uap:VisualElements>\n    </Application>\n  </Applications>\n\n  <Capabilities>\n    <Capability Name=\"internetClient\" />\n  </Capabilities>\n</Package>"
  },
  {
    "path": "FlutterBindingSample/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"FlutterBindingSample\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"FlutterBindingSample\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "FlutterBindingSample/Properties/Default.rd.xml",
    "content": "<!--\n    This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most\n    developers. However, you can modify these parameters to modify the behavior of the .NET Native\n    optimizer.\n\n    Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919\n\n    To fully enable reflection for App1.MyClass and all of its public/private members\n    <Type Name=\"App1.MyClass\" Dynamic=\"Required All\"/>\n\n    To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32\n    <TypeInstantiation Name=\"App1.AppClass\" Arguments=\"System.Int32\" Activate=\"Required Public\" />\n\n    Using the Namespace directive to apply reflection policy to all the types in a particular namespace\n    <Namespace Name=\"DataClasses.ViewModels\" Serialize=\"All\" />\n-->\n\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Application>\n    <!--\n      An Assembly element with Name=\"*Application*\" applies to all assemblies in\n      the application package. The asterisks are not wildcards.\n    -->\n    <Assembly Name=\"*Application*\" Dynamic=\"Required All\" />\n    \n    \n    <!-- Add your application specific runtime directives here. -->\n\n\n  </Application>\n</Directives>"
  },
  {
    "path": "FlutterSDK/FlutterSDK.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <NoWarn>1701;1702;0105</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\FlutterBinding\\FlutterBinding.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"src\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "FlutterSDK/Mappings/Global.cs",
    "content": "﻿using FlutterSDK.Animation.Animation;\nusing FlutterSDK.Widgets.Framework;\nusing FlutterSDK.Widgets.Navigator;\nusing SkiaSharp;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace FlutterSDK.Foundation.Annotations { }\nnamespace FlutterSDK\n{\n    // Instead of changing up code, here I have implemented a number of common things, to tie their approach to .NET\n\n    public delegate void AnimationStatusListener(AnimationStatus status);\n\n    public delegate bool RoutePredicate(Route<object> route);\n\n    public delegate Task<bool> WillPopCallback();\n\n    public delegate void TickerCallback(TimeSpan elapsed);\n\n    public delegate void DataColumnSortCallback(int columnIndex, bool ascending);\n\n    public delegate void RegisterServiceExtensionCallback(string name, ServiceExtensionCallback callback);\n\n    public delegate void ElementVisitor(Element element);\n\n    /// <summary>\n    /// Signature for service extensions.\n    /// The returned map must not contain the keys \"type\" or \"method\", as\n    /// they will be replaced before the value is sent to the client. The\n    /// \"type\" key will be set to the string `_extensionType` to indicate\n    /// that this is a return value from a service extension, and the\n    /// \"method\" key will be set to the full name of the method.\n    /// </summary>\n    public delegate Task<Dictionary<string, object>> ServiceExtensionCallback(Dictionary<string, string> parameters);\n\n    public interface IException { }\n\n    public class RegExp\n    {\n\n    }\n    public class StreamSubscription<T> { }\n    public class File\n    {\n\n    }\n    \n\n    public class SplayTreeMap<K, V> : Dictionary<K, V> { }\n\n    public class SendPort { }\n\n    public class Uint8Buffer { }\n\n    public class Element\n    {\n\n    }\n\n    public class Picture\n    {\n\n    }\n\n    public class EngineLa\n    {\n\n    }\n    \n    public class Pattern\n    { }\n\n\n    public class Float32List\n    {\n\n    }\n\n    public class Int32List\n    {\n\n    }\n\n    public class Comparable<T>\n    {\n        public Comparable<T> Compare(Comparable<T> a, Comparable<T> b)\n        {\n            return null;\n        }\n    }\n\n\n    public class Int64List\n    {\n\n    }\n\n    public class Float64List\n    {\n\n    }\n\n    public class Uint8List: List<ushort>\n    {\n\n    }\n\n    public enum TextDirection\n    {\n        ltr,\n        rtl\n    }\n\n    public enum TextAlign\n    {\n        left\n    }\n\n    public class Matrix4 // TODO\n    {\n\n    }\n\n    public class Function\n    { }\n\n    public class Radius\n    { }\n\n    public class LinkedHashSet<T> : HashSet<T> { }\n\n    public class Completer<T> // todo\n    {\n        public Future<T> future { get; set; }\n\n        public void complete(T callback)\n        {\n\n        }\n    }\n\n    public class Stream<T> // todo\n    {\n\n    }\n\n    public class Timeline\n    {\n\n    }\n\n    public class Null // todo\n    { }\n\n    public class StackTrace // This is really just a string equivalent in .NET land\n    { }\n\n    public class AssertionError : System.Exception\n    {\n        public AssertionError() { }\n        public AssertionError(string message): base(message) { }\n    }\n\n    public delegate void VoidCallback();\n\n    public class Rect { }\n    public class Color\n    {\n        public Color(uint? i)\n        {\n\n        }\n    }\n    public class Size\n    {\n        public Size(double? height)\n        {\n            this.Height = height;\n        }\n\n        public Size(double? width, double? height)\n        {\n            this.Width = width;\n            this.Height = height;\n        }\n\n        public double? Width { get; set; }\n        public double? Height { get; set; }\n    }\n\n    \n    public class Offset //TODO\n    {\n        public Offset() { }\n        public Offset(double? one, double? two) { }\n\n        public static Offset Zero => new Offset();\n\n        public double? dx { get; set; }\n        public double? dy { get; set; }\n    }\n\n    public class ByteData //TODO\n    { }\n\n    public class Future\n    {\n\n       \n\n    }\n\n    public class Future<T>: Future\n    {\n        public virtual Future<List<T>> Wait<T>(Iterable<Future<T>> futures, bool eagerError = default(bool), Action<T> cleanUp = default(Action<T>)) { throw new NotImplementedException(); }\n\n\n        public virtual Future<T> Any<T>(Iterable<Future<T>> futures) { throw new NotImplementedException(); }\n\n\n        public virtual Future<T> ForEach<T>(Iterable<T> elements, Func<FutureOr<T>, T> action) { throw new NotImplementedException(); }\n\n\n        public virtual Future<T> DoWhile(Func<FutureOr<bool>> action) { throw new NotImplementedException(); }\n\n        public Future() { }\n        public Future(Func<T> func) { }\n    }\n\n    public interface IFuture<T> { }\n\n    public class FutureOr<T>\n    {\n\n    }\n\n\n    public class HashSet<T> : System.Collections.Generic.HashSet<T>\n    {\n        public HashSet<T> From(List<T> newList)\n        {\n            var h = new HashSet<T>();\n            foreach (var item in newList)\n                h.Add(item);\n\n            return h;\n        }\n    }\n\n    public class Timer\n    {\n        public static void run(Action task)\n        {\n\n        }\n    }\n\n    public class AppLifecycleState\n    {\n        public const AppLifecycleState suspending = null;\n        public const AppLifecycleState paused = null;\n        public const AppLifecycleState resumed = null;\n        public const AppLifecycleState inactive = null;\n    }\n\n\n    public class StringBuffer // Similar to System.Text.StringBuilder\n    {\n        string _value = \"\";\n        public void Write(string value)\n        {\n            _value += value;\n        }\n\n        public void Writeln(string value) => _value += value + '\\n';\n        public void Writeln(char value) => _value += value + '\\n';\n        public void WriteAll(List<string> values, char separator) => _value += values.Join(separator);\n      \n        public override string ToString()\n        {\n            return _value;\n        }\n    }\n\n    public class Dictionary<T, V> : System.Collections.Generic.Dictionary<T, V>\n    {\n        public void remove(T element) => this.Remove(element);\n    }\n\n    public class Iterable<T> : List<T>\n    {\n    }\n\n    public class Iterator<T> : Iterable<T>, IIterator<T>\n    {\n        public T Current { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }\n    }\n\n    public interface IIterator<E>\n    {\n           E Current { get; set; }\n    }\n\n\n    public class IterableBase<E> : Iterator<E>, IEnumerable<E>\n    {\n        public virtual Iterable<T> Map<T>(Func<T, E> f) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<E> Where(Func<bool, E> test) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<T> Expand<T>(Func<Iterable<T>, E> f) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<E> Take(int count) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<E> TakeWhile(Func<bool, E> test) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<E> Skip(int count) { throw new NotImplementedException(); }\n\n\n        public virtual Iterable<E> SkipWhile(Func<bool, E> test) { throw new NotImplementedException(); }\n\n\n        public virtual List<E> ToList(bool growable = default(bool)) { throw new NotImplementedException(); }\n    }\n\n\n    public class Error : Exception { }\n\n    public static class Global\n    {\n\n        public static string Multiply(this string source, int multiplier)\n        {\n            StringBuilder sb = new StringBuilder(multiplier * source.Length);\n            for (int i = 0; i < multiplier; i++)\n            {\n                sb.Append(source);\n            }\n\n            return sb.ToString();\n        }\n\n        public static bool IsEmpty(this string value)\n        {\n            return string.IsNullOrEmpty(value);\n        }\n\n        public static bool Identical(object main, object other)\n         => main == other;\n\n        public static string DescribeIdentity(object obj)\n        {\n            return $\"{obj.GetType()}#{obj.GetHashCode()}\";\n        }\n\n        public static string ShortHash(object obj)\n        {\n            return obj.GetHashCode().ToUnsigned(20).ToRadixString(16).PadLeft(5, '0');\n        }\n\n        public static int ToUnsigned(this int value, int bits)\n        {\n            return value >> bits;\n        }\n\n        public static string ToRadixString(this int value, int radix)\n        {\n            var digits = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n\n            radix = Math.Abs(radix);\n            if (radix > digits.Length || radix < 2)\n                throw new ArgumentOutOfRangeException(\"radix\", radix, string.Format(\"Radix has to be > 2 and < {0}\", digits.Length));\n\n            string result = string.Empty;\n            int quotient = Math.Abs(value);\n            while (0 < quotient)\n            {\n                int temp = quotient % radix;\n                result = digits[temp] + result;\n                quotient /= radix;\n            }\n            return result;\n        }\n\n        public static double ToDouble(this int i) => Convert.ToDouble(i);\n        public static double ToDouble(this double d) => d;\n\n        public static string Join(this List<string> list, string separator) => string.Join(separator, list.ToArray());\n        public static string Join(this List<string> list, char separator) => string.Join(Convert.ToString(separator), list.ToArray());\n        public static double TruncateToDouble(this double d) => Math.Truncate(d);\n\n        public static string ToStringAsFixed(this double d, int value) => d.ToString($\"N{value}\");\n\n        public static double InMicroseconds(this TimeSpan timespan)\n        {\n            return timespan.TotalMilliseconds * 1000;\n        }\n\n        public static double Clamp(this double d, double lower, double upper)\n        {\n            if (d < lower)\n                return lower;\n\n            if (d > upper)\n                return upper;\n\n            return d;\n        }\n\n        public static bool IsFinite(this double d)\n        {\n            return !double.IsInfinity(d);\n        }\n\n        public static double Abs(this double d)\n        {\n            return (double)Math.Abs(Convert.ToDecimal(d));\n        }\n    }\n}"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Adam\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "**ABANDONED: While this project is technically feasible, it's not feasible for a couple of developers in their spare time to finish. It was only meant as a proof of concept and has taken several months to reach its current status and it may even take several more to complete. As stated, this project was never expected to be commercially viable. Due to the effort remaining and no future for this project, it was decided it was not worth our time to complete.**\n\n# Flutter for Xamarin\n\n*This project has no affiliation with Microsoft, Google or the Xamarin or Flutter teams.*\n\n**This project is still under construction, and a full working version does not exist yet. We will let everyone know when we finally get things running end to end.**\n\nThe project is designed to make the Flutter SDK available on the .NET Framework, initially with the supported platforms of:\n\n1) Xamarin.Android\n2) Xamarin.iOS\n3) UWP\n\nThere is no reason this couldn't also expand to any place where [SkiaSharp](https://github.com/mono/SkiaSharp) is supported.\n\nThis project is never expected to be commercially viable, unless it is picked up or supported by a larger company. As it currently stands, this is just a fun side project, done by a bunch of developers in their spare time. We offer no support for solutions ever built with this framework, or any guarantee of completion.\n\n# Overview\n\nTo make this work, numerous components need to come together.\n\n![alt text](https://github.com/adamped/xamarin.flutter/blob/master/XamarinFlutterProject.png?raw=true \"Overview of project\")\n\n## Transpiler\n\nThe transpiler, will convert the existing Flutter SDK (written in Dart) to C#, for consumption in .NET applications.\n\nUsing the DartAnalyzer, we analyze the Flutter SDK, and output C#.\n\n## Bindings\n\nFlutter Bindings will include the connection between SkiaSharp and the Flutter SDK. We will not be using the actual Flutter engine, though we may do in the future.\n\nDue to previous exploratory work, the Flutter engine is difficult to integrate with since we need to expose many C++ level APIs. Due to how this is implemented in the Flutter engine currently, it would require certain modifications and would be difficult to keep in sync with the master repository.\n\nHence, we will map the calls directly to SkiaSharp and Harfbuzz to draw directly on a SkiaCanvas. I could regret this, we shall see :)\n\n## Shell\n\nThe Shell, is where the Skia Canvas is initialized and platform level events are collected, and sent through to the Bindings project.\n\n# License\n\nAll code here is licensed under the [MIT license](LICENSE)\n"
  },
  {
    "path": "TRANSPILER_README.md",
    "content": "# Transpiler\n\nThis document details how to run the transpiler. It is currently a work in progress.\n\n## Dart Analyzer\n\nIn the AST folder is `analyzer.dart`, which uses the Dart Analyzer to create a Semantic Model of the Flutter SDK.\n\n### Running the Dart Analyzer\n\n1. The Flutter SDK isn't included in this project. Install it and make sure that its `bin` directory is in PATH.\n2.  Run `download-flutter.ps1` script in flutter sub directory (make sure that PATH from previous step is applied, or if it wasn't, run `flutter packages get` manually).\n\n3. Install [Dart SDK](https://www.dartlang.org/tools/sdk#install) on your computer.\n\n4. Make sure there is a DART_SDK environment  variable pointing to `dart_sdk` directory. Optionally add its bin directory to PATH (if not already).\n\n5. In a terminal window or command prompt, run `dart analyzer`.\n\nThis will run through the Flutter SDK and create an equivalent *.cs files.\n\n## Semantic Model\n\nTo generate the *.cs files, the Dart Analyzer creates a Semantic Model that is used by the writer.\n\n## CSharp Writer\n\nThe writer, will take the Semantic Model and output the transpiled C# files into the FlutterSDK project.\n"
  },
  {
    "path": "Xamarin.Flutter.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.28010.2036\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"FlutterSDK\", \"FlutterSDK\\FlutterSDK.csproj\", \"{0781218D-0BCF-4528-AA32-A1937572E43B}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{0D75E496-44EB-4553-B1D1-D16F2F2301ED}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.gitignore = .gitignore\n\t\tCODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md\n\t\tLICENSE = LICENSE\n\t\tREADME.md = README.md\n\t\tTRANSPILER_README.md = TRANSPILER_README.md\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"FlutterBinding\", \"FlutterBinding\\FlutterBinding.csproj\", \"{C9313643-3357-4872-9B00-03E2C79AD297}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Shell\", \"Shell\", \"{AEF05715-89B3-4BDE-96B4-A8C502ADD1E5}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flutter.Shell.UWP\", \"Flutter.Shell.UWP\\Flutter.Shell.UWP.csproj\", \"{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Sample\", \"Sample\", \"{A913B932-A596-428F-9B4B-F17692C41D1A}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flutter.Sample.UWP\", \"Flutter.Sample.UWP\\Flutter.Sample.UWP.csproj\", \"{F02BD326-5760-4246-9EDC-C41B489E965B}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Flutter\", \"Flutter\", \"{A3093869-0FE2-4929-8A5C-D384A14F0065}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\..\\Downloads\\model.json = ..\\..\\Downloads\\model.json\n\tEndProjectSection\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flutter.Shell.Droid\", \"Flutter.Shell.Droid\\Flutter.Shell.Droid.csproj\", \"{C9E1CAA4-53F3-4032-92A0-81F5322D446B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Flutter.Sample.Droid\", \"Flutter.Sample.Droid\\Flutter.Sample.Droid.csproj\", \"{48483C42-37B1-4258-BD46-8387A4FA71C1}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Flutter.Sample.App\", \"Flutter.Sample.App\\Flutter.Sample.App.csproj\", \"{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"FlutterBindingSample\", \"FlutterBindingSample\\FlutterBindingSample.csproj\", \"{2AFB0021-0EE7-4F30-9598-22E269F355CA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|x64.Build.0 = Debug|x64\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|x86.ActiveCfg = Debug|x86\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Debug|x86.Build.0 = Debug|x86\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|ARM.Build.0 = Release|ARM\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|x64.ActiveCfg = Release|x64\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|x64.Build.0 = Release|x64\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|x86.ActiveCfg = Release|x86\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14}.Release|x86.Build.0 = Release|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|Any CPU.ActiveCfg = Debug|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|ARM.Deploy.0 = Debug|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x64.Build.0 = Debug|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x86.ActiveCfg = Debug|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x86.Build.0 = Debug|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Debug|x86.Deploy.0 = Debug|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|Any CPU.ActiveCfg = Release|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|ARM.Build.0 = Release|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|ARM.Deploy.0 = Release|ARM\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x64.ActiveCfg = Release|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x64.Build.0 = Release|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x64.Deploy.0 = Release|x64\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x86.ActiveCfg = Release|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x86.Build.0 = Release|x86\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B}.Release|x86.Deploy.0 = Release|x86\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B}.Release|x86.Build.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|ARM.Deploy.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x64.Deploy.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Debug|x86.Deploy.0 = Debug|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|Any CPU.Deploy.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|ARM.Deploy.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x64.Build.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x64.Deploy.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x86.Build.0 = Release|Any CPU\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1}.Release|x86.Deploy.0 = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|x64.Build.0 = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279}.Release|x86.Build.0 = Release|Any CPU\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|Any CPU.ActiveCfg = Debug|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|ARM.Deploy.0 = Debug|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x64.Build.0 = Debug|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x86.ActiveCfg = Debug|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x86.Build.0 = Debug|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Debug|x86.Deploy.0 = Debug|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|Any CPU.ActiveCfg = Release|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|ARM.Build.0 = Release|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|ARM.Deploy.0 = Release|ARM\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x64.ActiveCfg = Release|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x64.Build.0 = Release|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x64.Deploy.0 = Release|x64\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x86.ActiveCfg = Release|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x86.Build.0 = Release|x86\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA}.Release|x86.Deploy.0 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{0781218D-0BCF-4528-AA32-A1937572E43B} = {A3093869-0FE2-4929-8A5C-D384A14F0065}\n\t\t{C9313643-3357-4872-9B00-03E2C79AD297} = {A3093869-0FE2-4929-8A5C-D384A14F0065}\n\t\t{A5BF7067-2A28-4002-AEB4-1965D0DEDC14} = {AEF05715-89B3-4BDE-96B4-A8C502ADD1E5}\n\t\t{F02BD326-5760-4246-9EDC-C41B489E965B} = {A913B932-A596-428F-9B4B-F17692C41D1A}\n\t\t{C9E1CAA4-53F3-4032-92A0-81F5322D446B} = {AEF05715-89B3-4BDE-96B4-A8C502ADD1E5}\n\t\t{48483C42-37B1-4258-BD46-8387A4FA71C1} = {A913B932-A596-428F-9B4B-F17692C41D1A}\n\t\t{E0FB1BF8-E32C-4A8A-9AE6-E501CC68F279} = {A913B932-A596-428F-9B4B-F17692C41D1A}\n\t\t{2AFB0021-0EE7-4F30-9598-22E269F355CA} = {A3093869-0FE2-4929-8A5C-D384A14F0065}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {FC817DF6-985F-441B-A47E-2539BCDEB3C1}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "testbed/test.dart",
    "content": "class Widget {}\nclass Row {\n  Row(<Widget> children) {}\n }\n}\n\nclass OutlineButton {\n  OutlineButton({Row child});\n}\n\nclass _OutlineButtonWithIcon extends OutlineButton {\n  _OutlineButtonWithIcon({@required Widget icon,\n    @required Widget label,\n  }) : super(\n         child: Row(\n           children: <Widget>[\n             icon,\n             const SizedBox(width: 8.0),\n             label,\n           ],\n         ),\n       );\n}"
  }
]