浏览代码

Merge branch 'master' into translate

/main
GitHub 6 年前
当前提交
a0e4cb7c
共有 539 个文件被更改,包括 5207 次插入1232 次删除
  1. 12
      .gitignore
  2. 7
      .npmignore
  3. 6
      CHANGELOG.md
  4. 28
      CONTRIBUTING.md
  5. 27
      LICENSE.md
  6. 12
      README-ZH.md
  7. 93
      README.md
  8. 4
      Runtime/Resources/UIWidgets_canvas.cginc
  9. 46
      Runtime/animation/listener_helpers.mixin.gen.cs
  10. 19
      Runtime/async/coroutine.cs
  11. 5
      Runtime/debugger/inspector_service.cs
  12. 8
      Runtime/debugger/inspector_treeview.cs
  13. 21
      Runtime/debugger/inspector_window.cs
  14. 93
      Runtime/editor/editor_window.cs
  15. 9
      Runtime/engine/DisplayMetrics.cs
  16. 42
      Runtime/engine/input_utils.cs
  17. 1
      Runtime/flow/clip_path_layer.cs
  18. 1
      Runtime/flow/clip_rect_layer.cs
  19. 1
      Runtime/flow/clip_rrect_layer.cs
  20. 2
      Runtime/flow/opacity_layer.cs
  21. 2
      Runtime/flow/picture_layer.cs
  22. 24
      Runtime/flow/raster_cache.cs
  23. 3
      Runtime/foundation/basic_types.cs
  24. 38
      Runtime/foundation/debug.cs
  25. 31
      Runtime/foundation/node.mixin.gen.cs
  26. 8
      Runtime/foundation/node.mixin.njk
  27. 24
      Runtime/gestures/monodrag.cs
  28. 9
      Runtime/gestures/recognizer.cs
  29. 30
      Runtime/material/arc.cs
  30. 3
      Runtime/material/button.cs
  31. 69
      Runtime/material/button_theme.cs
  32. 3
      Runtime/material/color_scheme.cs
  33. 10
      Runtime/material/constants.cs
  34. 53
      Runtime/material/debug.cs
  35. 8
      Runtime/material/drawer.cs
  36. 7
      Runtime/material/drawer_header.cs
  37. 2
      Runtime/material/expand_icon.cs
  38. 6
      Runtime/material/expansion_panel.cs
  39. 5
      Runtime/material/expansion_tile.cs
  40. 8
      Runtime/material/icon_button.cs
  41. 998
      Runtime/material/icons.cs
  42. 2
      Runtime/material/ink_decoration.cs
  43. 5
      Runtime/material/ink_highlight.cs
  44. 43
      Runtime/material/ink_ripple.cs
  45. 52
      Runtime/material/ink_splash.cs
  46. 3
      Runtime/material/ink_well.cs
  47. 7
      Runtime/material/list_tile.cs
  48. 14
      Runtime/material/material.cs
  49. 10
      Runtime/material/scrollbar.cs
  50. 108
      Runtime/material/text_selection.cs
  51. 3
      Runtime/material/text_theme.cs
  52. 12
      Runtime/material/theme.cs
  53. 359
      Runtime/material/theme_data.cs
  54. 7
      Runtime/material/tooltip.cs
  55. 15
      Runtime/painting/image_provider.cs
  56. 41
      Runtime/painting/image_resolution.cs
  57. 4
      Runtime/painting/text_painter.cs
  58. 41
      Runtime/painting/text_span.cs
  59. 56
      Runtime/painting/text_style.cs
  60. 12
      Runtime/promise/Promise.cs
  61. 11
      Runtime/promise/Promise_NonGeneric.cs
  62. 3
      Runtime/rendering/binding.cs
  63. 11
      Runtime/rendering/box.cs
  64. 18
      Runtime/rendering/box.mixin.gen.cs
  65. 514
      Runtime/rendering/editable.cs
  66. 221
      Runtime/rendering/layer.cs
  67. 24
      Runtime/rendering/object.cs
  68. 90
      Runtime/rendering/object.mixin.gen.cs
  69. 19
      Runtime/rendering/paragraph.cs
  70. 581
      Runtime/rendering/proxy_box.cs
  71. 20
      Runtime/rendering/proxy_box.mixin.gen.cs
  72. 87
      Runtime/rendering/stack.cs
  73. 8
      Runtime/rendering/viewport.cs
  74. 9
      Runtime/rendering/viewport_offset.cs
  75. 27
      Runtime/scheduler/binding.cs
  76. 377
      Runtime/service/keyboard.cs
  77. 16
      Runtime/service/system_chrome.cs
  78. 27
      Runtime/service/text_formatter.cs
  79. 305
      Runtime/service/text_input.cs
  80. 60
      Runtime/ui/compositing.cs
  81. 103
      Runtime/ui/geometry.cs
  82. 14
      Runtime/ui/matrix.cs
  83. 47
      Runtime/ui/painting/canvas.cs
  84. 266
      Runtime/ui/painting/canvas_impl.cs
  85. 119
      Runtime/ui/painting/canvas_shader.cs
  86. 33
      Runtime/ui/painting/painting.cs
  87. 230
      Runtime/ui/painting/path.cs
  88. 20
      Runtime/ui/painting/shader.cs
  89. 2
      Runtime/ui/painting/tessellation_generator.cs
  90. 171
      Runtime/ui/painting/txt/font_manager.cs
  91. 83
      Runtime/ui/painting/txt/mesh_generator.cs
  92. 23
      Runtime/ui/painting/txt/text_blob.cs
  93. 148
      Runtime/ui/text.cs
  94. 15
      Runtime/ui/txt/layout.cs
  95. 33
      Runtime/ui/txt/linebreaker.cs
  96. 2
      Runtime/ui/txt/paint_record.cs
  97. 96
      Runtime/ui/txt/paragraph.cs
  98. 12
      Runtime/ui/txt/paragraph_builder.cs
  99. 6
      Runtime/ui/txt/styled_runs.cs
  100. 16
      Runtime/ui/txt/word_separate.cs

12
.gitignore


node_modules/
npm-debug.log
yarn-error.log
artifacts/**
build/**
.build_script/**
node_modules/**
.DS_Store
.npmrc
!Documentation~
!.Documentation
npm-debug.log
build.sh.meta
build.bat.meta

7
.npmignore


build.sh.meta
build.bat
build.bat.meta
automation/**
utr_output/**
.Editor/**
.yamato/**
*.zip*
scripts~/**

6
CHANGELOG.md


The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [0.1.0] - 2017-MM-DD
## [1.0.0-preview] - 2019-03-01
### This is the first release of *Unity Package \<Your package name\>*.
### This is the first release of *Unity Package UIWidgets*.
*Short description of this release*
*just the first release*

28
CONTRIBUTING.md


# Contributing
## If you are interested in contributing, here are some ground rules:
* ... Define guidelines & rules for what contributors need to know to successfully make Pull requests against your repo ...
### Code Style (using JetBrains Rider)
1. **Import the Customized Code Cleanup Settings**: Open Preferences -> Manage Layers,
Choose 'Solution "\<YourProjectName\>" personal' and Click "Add Layer" ("+") -> "Open Settings File...".
and Open the file "UIWidgetCleanupPlugin.DotSettings" under \<YourProjectPath\>/Packages/com.unity.uiwidgets/"
2. **Cleanup Code style using the Customized Code Cleanup Settings**: Open Code -> Code Cleanup,
Pick a Cleanup scope as you want and Choose "UIWidgets" as the "Code cleanup profile", then click "OK"
3. **Refine Code Style Rules**: Edit the ".editorconfig" file under \<YourProjectPath\>/Packages/com.unity.uiwidgets/". Visit
https://www.jetbrains.com/help/rider/EditorConfig_Index.html for the detailed.
### Generate Code.
Code files ending with ".gen.cs" are auto generated. Follow these steps to generate them:
1. **Go to scripts Folder and Run npm install**:
```
cd <YourProjectPath>/Packages/com.unity.uiwidgets/scripts~
npm install
```
2. **Run the codegen Command**:
```
node uiwidgets-cli.js codegen . generate mixin code
```
## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement)
By making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions.

27
LICENSE.md


Copyright 2019 The UIWidget Authors. All rights reserved.
Copyright 2014 The Chromium Authors. All rights reserved.
UIWidgets copyright © 2019 Unity Technologies ApS
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.

12
README-ZH.md


</td>
</tr></table></div>
## 使用要求
#### Unity

访问我们的Github存储库 [https://github.com/UnityTech/UIWidgets](https://github.com/UnityTech/UIWidgets)下载最新的UIWidgets包。
将下载的包文件夹移动到 Unity项目的Package文件夹中。
将下载的包文件夹移动到Unity项目的Package文件夹中。
通常,你可以在控制台(或终端)应用程序中输入下面的代命令来完成这个操作:
通常,你可以在控制台(或终端)应用程序中输入下面的代码来完成这个操作:
```none
cd <YourProjectPath>/Packages

UIWidgets应用是用**C#脚本**来编写的。 请按照以下步骤创建应用程序并在Unity编辑器中播放。
1. 创建一个新C#脚本,命名为“ExampleCanvas.cs”,并将以下代码粘贴到其中。
```none
using System.Collections.Generic;
using Unity.UIWidgets.animation;

new Text("Counter: " + this.counter),
new GestureDetector(
onTap: () => {
this.setState(()
=> {
this.setState(() => {
this.counter++;
});
},

## 如何贡献
请查看[CONTRIBUTING.md](CONTRIBUTING.md)

93
README.md


# UIWidgets
[中文](README-ZH.md)
## Introduction

CPU/GPU Profiling, FPS Profiling.
### Example
<div style="text-align: center"><table><tr>
<td style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190323/p/images/2a27606f-a2cc-4c9f-9e34-bb39ae64d06c_uiwidgets1.gif" width="200"/>
</td>
<td style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190323/p/images/097a7c53-19b3-4e0a-ad27-8ec02506905d_uiwidgets2.gif" width="200" />
</td>
<td style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190323/p/images/1f03c1d0-758c-4dde-b3a9-2f5f7216b7d9_uiwidgets3.gif" width="200"/>
</td>
<td style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190323/p/images/a8884fbd-9e7c-4bd7-af46-0947e01d01fd_uiwidgets4.gif" width="200"/>
</td>
</tr></table></div>
## Requirement
#### Unity

A UIWidgets App is written in **C# Scripts**. Please follow the steps to create an App and play it
in Unity Editor.
1. Create a new C# Script named "ExampleCanvas.cs" and paste the following codes into it.
1. Create a new C# Script named "UIWidgetsExample.cs" and paste the following codes into it.
using Unity.UIWidgets.animation;
using Unity.UIWidgets.ui;
using UnityEngine;
using FontStyle = Unity.UIWidgets.ui.FontStyle;
public class ExampleCanvas : WidgetCanvas {
protected override void OnEnable() {
base.OnEnable();
public class UIWidgetsExample : UIWidgetsPanel {
protected override void Awake() {
base.Awake();
// if you want to use your own font or font icons.
// use the font family name instead of the file name in FontStyle.fontFamily.
// you can get the font family name by clicking the font file and check its Inspector.
// FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"));
// if you want to use your own font or font icons.
// FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "font family name");
// load custom font with weight & style. The font weight & style corresponds to fontWeight, fontStyle of
// a TextStyle object
// FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "Roboto", FontWeight.w500,
// FontStyle.italic);
// add material icons, familyName must be "Material Icons"
// FontManager.instance.addFont(Resources.Load<Font>(path: "path to material icons"), "Material Icons");
protected override Widget getWidget() {
return new ExampleApp();
protected override Widget createWidget() {
return new WidgetsApp(
home: new ExampleApp(),
pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) =>
new PageRouteBuilder(
settings: settings,
pageBuilder: (BuildContext context, Animation<float> animation,
Animation<float> secondaryAnimation) => builder(context)
)
);
}
class ExampleApp : StatefulWidget {

new GestureDetector(
onTap: () => {
this.setState(()
=> {
=> {
this.counter++;
});
},

## Learn
#### Samples
You can find many UIWidgets App samples in the UIWidgets package in the **Samples** folder.
You can find many UIWidgets App samples in the UIWidgets package in the **Samples** folder.
To get started, the UIWidgetsTheatre scene provides you
a list of carefully selected samples to start with.
You can also try UIWidgets-based Editor windows by clicking **UIWidgetsTest** on the main menu
and open one of the dropdown samples.

you can refer to Flutter Wiki to access detailed descriptions of UIWidgets APIs
from those of their Flutter counterparts.
#### FAQ
| Question | Answer |

| Any IDE recommendation for UIWidgets? | **Rider, VSCode(Open .sln)** |
## How to Contribute
If you want to join us, please contact us via Github and we will respond as soon as possible.
#### Code Style
1. **Import the Customized Code Cleanup Settings**: Open Preferences -> Manage Layers,
Choose 'Solution "\<YourProjectName\>" personal' and Click "Add Layer" ("+") -> "Open Settings File...".
and Open the file "UIWidgetCleanupPlugin.DotSettings" under \<YourProjectPath\>/Packages/com.unity.uiwidgets/"
2. **Cleanup Code style using the Customized Code Cleanup Settings**: Open Code -> Code Cleanup,
Pick a Cleanup scope as you want and Choose "UIWidgets" as the "Code cleanup profile", then click "OK"
3. **Refine Code Style Rules**: Edit the ".editorconfig" file under \<YourProjectPath\>/Packages/com.unity.uiwidgets/". Visit
https://www.jetbrains.com/help/rider/EditorConfig_Index.html for the detailed.
#### Generate njk Code
1. **Go to scripts Folder and Run npm install**:
```
cd <YourProjectPath>/Packages/com.unity.uiwidgets/scripts
npm install
```
2. **Run the codegen Command**:
```
node uiwidgets-cli.js codegen . generate mixin code
```
Check [CONTRIBUTING.md](CONTRIBUTING.md)

4
Runtime/Resources/UIWidgets_canvas.cginc


half4 color = half4(0, 0, 0, 0);
float2 coord = i.ftcoord - _mf_radius * _mf_imgInc;
int width = _mf_radius * 2 + 1;
int width = _mf_radius * 2.0 + 1; // use 2.0 to avoid "bitfieldInsert"
[unroll(25)]
for (int i = 0; i < width; i++) {
color += tex2D(_tex, coord) * _mf_kernel[i];
coord += _mf_imgInc;

46
Runtime/animation/listener_helpers.mixin.gen.cs


using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.animation {
public abstract class AnimationLazyListenerMixinAnimation<T> : Animation<T> {
int _listenerCounter = 0;

}
public abstract class AnimationEagerListenerMixinAnimation<T> : Animation<T> {
protected void didRegisterListener() {
}

}
public abstract class
AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T> {
public abstract class AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T> {
readonly ObserverList<VoidCallback> _listeners = new ObserverList<VoidCallback>();
public override void addListener(VoidCallback listener) {

if (this._listeners.Contains(listener)) {
listener();
}
}
catch (Exception exception) {
} catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "animation library",

}
public abstract class
AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> : AnimationEagerListenerMixinAnimation<T> {
public abstract class AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> : AnimationEagerListenerMixinAnimation<T> {
readonly ObserverList<VoidCallback> _listeners = new ObserverList<VoidCallback>();
public override void addListener(VoidCallback listener) {

if (this._listeners.Contains(listener)) {
listener();
}
}
catch (Exception exception) {
} catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "animation library",

}
public abstract class
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> :
AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> {
public abstract class AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> {
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>();
public override void addStatusListener(AnimationStatusListener listener) {

if (this._statusListeners.Contains(listener)) {
listener(status);
}
}
catch (Exception exception) {
} catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "animation library",

}
public abstract class
AnimationLocalStatusListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T
> {
public abstract class AnimationLocalStatusListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T> {
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>();
public override void addStatusListener(AnimationStatusListener listener) {

if (this._statusListeners.Contains(listener)) {
listener(status);
}
}
catch (Exception exception) {
} catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "animation library",

}
public abstract class
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> :
AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> {
public abstract class AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> : AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> {
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>();
public override void addStatusListener(AnimationStatusListener listener) {

if (this._statusListeners.Contains(listener)) {
listener(status);
}
}
catch (Exception exception) {
} catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "animation library",

}
}
}
}

19
Runtime/async/coroutine.cs


internal volatile Exception lastError;
internal bool isDone;
readonly Promise<object> _promise = new Promise<object>();
readonly Promise<object> _promise = new Promise<object>(isSync: true);
public IPromise<object> promise {
get { return this._promise; }

this._routine = routine;
this._window = window;
this._isBackground = isBackground;
if (isBackground && BackgroundCallbacks.getInstance() != null) {
this._unhook = BackgroundCallbacks.getInstance().addCallback(this._moveNext);

this._moveNext(true); // try to run the first enumeration in the current loop.
this._isBackground = isBackground;
this._moveNext(false);
}
void _moveNext(bool firstTime) {
D.assert(!this.isDone);
var lastError = this.lastError;

return;
}
bool hasNext;
bool hasNext = true;
hasNext = this._processIEnumeratorRecursive(this._routine);
if (firstTime) {
hasNext = this._routine.MoveNext();
}
if (hasNext) {
hasNext = this._processIEnumeratorRecursive(this._routine);
}
}
catch (Exception ex) {
this.stop(ex);

5
Runtime/debugger/inspector_service.cs


using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.debugger {

public bool active {
get { return this.window.alive; }
}
public bool debugEnabled {
get { return D.debugEnabled; }
}
public void close() {

8
Runtime/debugger/inspector_treeview.cs


public override string displayName {
get { return this.node.name + this.node.description; }
get {
if (this.node.showName && !string.IsNullOrEmpty(this.node.name)) {
return $"{this.node.name}{this.node.separator} {this.node.description}";
}
return this.node.description;
}
}
}

21
Runtime/debugger/inspector_window.cs


bool m_DebugPaintLayer;
bool m_ShowDebugPaintToggles;
GUIStyle m_MessageStyle;
readonly List<InspectorPanel> m_Panels = new List<InspectorPanel>();
Rect m_DebugPaintTogglesRect;

window.Show();
}
void OnEnable() {
this.titleContent = new GUIContent("UIWidgets Inspector");
}
if (this.m_InspectorService != null) {
if (this.m_InspectorService != null && this.m_InspectorService.debugEnabled) {
if (GUILayout.Button("Refersh", EditorStyles.toolbarButton)) {
foreach (var panel in this.m_Panels) {
panel.MarkNeedReload();

EditorGUILayout.Space();
if (this.m_InspectorService != null) {
if (this.m_InspectorService != null && this.m_InspectorService .debugEnabled) {
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(false));
this.m_Panels.Each((pannel, index) => {
if (GUILayout.Toggle(this.m_PanelIndex == index, pannel.title, EditorStyles.toolbarButton,

if (shouldHandleGUI) {
this.m_Panels[this.m_PanelIndex].OnGUI();
}
} else if (this.m_InspectorService != null) { // debug not enabled
if (this.m_MessageStyle == null) {
this.m_MessageStyle = new GUIStyle(GUI.skin.label);
this.m_MessageStyle.fontSize = 16;
this.m_MessageStyle.alignment = TextAnchor.MiddleCenter;
this.m_MessageStyle.padding = new RectOffset(20, 20, 40, 0);
}
GUILayout.Label("You're not in UIWidgets Debug Mode.\nPlease define UIWidgets_DEBUG " +
"symbols at \"Player Settings => Scripting Define Symbols\".",
this.m_MessageStyle, GUILayout.ExpandWidth(true));
}
if (this.m_ShowDebugPaintToggles) {

93
Runtime/editor/editor_window.cs


using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;

this.wantsMouseEnterLeaveWindow = true;
}
void OnEnable() {
protected virtual void Awake() {
}
protected virtual void OnEnable() {
if (this._windowAdapter == null) {
this._windowAdapter = new EditorWindowAdapter(this);
}

var rootRenderBox = this.rootRenderBox();
RenderBox rootRenderBox;
using (this._windowAdapter.getScope()) {
rootRenderBox = this.createRenderBox();
}
this._windowAdapter.attachRootWidget(this.rootWidget());
Widget rootWidget;
using (this._windowAdapter.getScope()) {
rootWidget = this.createWidget();
}
this._windowAdapter.attachRootWidget(rootWidget);
void OnDisable() {
protected virtual void OnDisable() {
void OnGUI() {
protected virtual void OnGUI() {
void Update() {
float? lastUpdateTime;
protected virtual void Update() {
if (this.lastUpdateTime != null) {
float deltaTime = (float)EditorApplication.timeSinceStartup - this.lastUpdateTime.Value;
PerformanceUtils.instance.updateDeltaTime(deltaTime);
}
this.lastUpdateTime = (float) EditorApplication.timeSinceStartup;
protected virtual RenderBox rootRenderBox() {
protected virtual RenderBox createRenderBox() {
protected abstract Widget rootWidget();
protected abstract Widget createWidget();
}
public class EditorWindowAdapter : WindowAdapter {

public override void scheduleFrame(bool regenerateLayerTree = true) {
base.scheduleFrame(regenerateLayerTree);
this.editorWindow.Repaint();
}
protected override bool hasFocus() {
return EditorWindow.focusedWindow == this.editorWindow;
}
public override GUIContent titleContent {

public abstract class WindowAdapter : Window {
static readonly List<WindowAdapter> _windowAdapters = new List<WindowAdapter>();
public static IEnumerable<WindowAdapter> windowAdapters {
public static List<WindowAdapter> windowAdapters {
get { return _windowAdapters; }
}

}
}
WidgetsBinding _binding;
internal WidgetsBinding _binding;
float _lastWindowWidth;
float _lastWindowHeight;

readonly TextInput _textInput = new TextInput();
readonly Rasterizer _rasterizer = new Rasterizer();
readonly ScrollInput _scrollInput = new ScrollInput();

protected virtual void updateSafeArea() {
}
protected abstract bool hasFocus();
public void OnEnable() {
this._devicePixelRatio = this.queryDevicePixelRatio();
var size = this.queryWindowSize();

}
public void OnDisable() {
using (this.getScope()) {
this._binding.detachRootWidget();
}
_windowAdapters.Remove(this);
this._alive = false;

}
public override IDisposable getScope() {
instance = this;
WindowAdapter oldInstance = (WindowAdapter) _instance;
_instance = this;
WidgetsBinding.instance = this._binding;
SchedulerBinding._instance = this._binding;
return new WindowDisposable(this);
return new WindowDisposable(this, oldInstance);
readonly WindowAdapter _oldWindow;
public WindowDisposable(WindowAdapter window) {
public WindowDisposable(WindowAdapter window, WindowAdapter oldWindow) {
this._oldWindow = oldWindow;
D.assert(instance == this._window);
instance = null;
D.assert(_instance == this._window);
_instance = this._oldWindow;
D.assert(WidgetsBinding.instance == this._window._binding);
WidgetsBinding.instance = null;
D.assert(SchedulerBinding._instance == this._window._binding);
SchedulerBinding._instance = this._oldWindow?._binding;
}
}

}
}
if (this._textInput != null) {
this._textInput.keyboardManager.OnGUI();
}
RawKeyboard.instance._handleKeyEvent(Event.current);
TextInput.OnGUI();
}
void _updateScrollInput() {

public void Update() {
Timer.update();
bool hasFocus = this.hasFocus();
WidgetsBinding.instance.focusManager.focusNone(!hasFocus);
if (this._textInput != null) {
this._textInput.keyboardManager.Update();
}
TextInput.Update();
this._timerProvider.update(this.flushMicrotasks);
this.flushMicrotasks();
}

}
}
public override TextInput textInput {
get { return this._textInput; }
public void attachRootWidget(Func<Widget> root) {
using (this.getScope()) {
this._binding.attachRootWidget(root());
}
internal void _forceRepaint() {
using (this.getScope()) {
RenderObjectVisitor visitor = null;

9
Runtime/engine/DisplayMetrics.cs


}
public interface DisplayMetrics {
void OnEnable();
float DevicePixelRatio { get; }
float devicePixelRatio { get; }
}
public class PlayerDisplayMetrics: DisplayMetrics {

public void OnEnable() {
}
public void OnGUI() {
}

public float DevicePixelRatio {
public float devicePixelRatio {
get {
if (this._devicePixelRatio > 0) {
return this._devicePixelRatio;

42
Runtime/engine/input_utils.cs


using Unity.UIWidgets.foundation;
public static class InputUtils {
static class InputUtils {
const int preservedPointerKeyNum = 10;
const int preservedKeyNum = 10;
const int preservedMouseKeyNum = 100;
const int fingerKeyStart = preservedKeyNum + preservedMouseKeyNum;
public static PointerDeviceKind getPointerDeviceKind() {
#if UNITY_IOS || UNITY_ANDROID
return PointerDeviceKind.touch;
#else
return PointerDeviceKind.mouse;
#endif
public static PointerDeviceKind getPointerDeviceKind(PointerEventData eventData) {
return isTouchEvent(eventData) ? PointerDeviceKind.touch : PointerDeviceKind.mouse;
#if UNITY_IOS || UNITY_ANDROID
return getTouchFingerKey(eventData.pointerId);
#else
return getMouseButtonKey((int) eventData.button);
#endif
return isTouchEvent(eventData)
? getTouchFingerKey(eventData.pointerId)
: getMouseButtonKey((int) eventData.button);
}
public static int getScrollButtonKey() {

public static int getMouseButtonKey(int buttonId) {
return buttonId + preservedPointerKeyNum;
D.assert(buttonId < preservedMouseKeyNum);
return buttonId + preservedKeyNum;
}
static int getTouchFingerKey(int fingerId) {
return fingerId + fingerKeyStart;
}
static bool isTouchEvent(PointerEventData eventData) {
//pointerId >= 0 : touches
//ref: https://docs.unity3d.com/ScriptReference/EventSystems.PointerEventData-pointerId.html
return eventData.pointerId >= 0;
public static int getTouchFingerKey(int fingerId) {
return fingerId + preservedPointerKeyNum;
static bool isMouseEvent(PointerEventData eventData) {
//pointerId = -1, -2, -3 : mouse buttons
//ref: https://docs.unity3d.com/ScriptReference/EventSystems.PointerEventData-pointerId.html
return eventData.pointerId < 0;
}
}
}

1
Runtime/flow/clip_path_layer.cs


var clipPathBounds = this._clipPath.getBounds();
context.cullRect = context.cullRect.intersect(clipPathBounds);
this.paintBounds = Rect.zero;
if (!context.cullRect.isEmpty) {
var childPaintBounds = Rect.zero;
this.prerollChildren(context, matrix, ref childPaintBounds);

1
Runtime/flow/clip_rect_layer.cs


context.cullRect = context.cullRect.intersect(this._clipRect);
this.paintBounds = Rect.zero;
if (!context.cullRect.isEmpty) {
var childPaintBounds = Rect.zero;
this.prerollChildren(context, matrix, ref childPaintBounds);

1
Runtime/flow/clip_rrect_layer.cs


var clipPathBounds = this._clipRRect.outerRect;
context.cullRect = context.cullRect.intersect(clipPathBounds);
this.paintBounds = Rect.zero;
if (!context.cullRect.isEmpty) {
var childPaintBounds = Rect.zero;
this.prerollChildren(context, matrix, ref childPaintBounds);

2
Runtime/flow/opacity_layer.cs


public override void preroll(PrerollContext context, Matrix3 matrix) {
var childMatrix = new Matrix3(matrix);
childMatrix.postTranslate(this._offset.dx, this._offset.dy); // TOOD: pre or post? https://github.com/flutter/engine/pull/7945
childMatrix.preTranslate(this._offset.dx, this._offset.dy); // TOOD: pre or post? https://github.com/flutter/engine/pull/7945
base.preroll(context, childMatrix);

2
Runtime/flow/picture_layer.cs


public override void preroll(PrerollContext context, Matrix3 matrix) {
if (context.rasterCache != null) {
Matrix3 ctm = new Matrix3(matrix);
ctm.postTranslate(this._offset.dx, this._offset.dy); // TOOD: pre or post? https://github.com/flutter/engine/pull/7945
ctm.preTranslate(this._offset.dx, this._offset.dy); // TOOD: pre or post? https://github.com/flutter/engine/pull/7945
ctm[2] = ctm[2].alignToPixel(context.devicePixelRatio);
ctm[5] = ctm[5].alignToPixel(context.devicePixelRatio);

24
Runtime/flow/raster_cache.cs


public readonly float devicePixelRatio;
public void draw(Canvas canvas) {
var bounds = canvas.getTotalMatrix().mapRect(this.logicalRect);
var bounds = canvas.getTotalMatrix().mapRect(this.logicalRect).roundOut(this.devicePixelRatio);
D.assert(() => {
var textureWidth = Mathf.CeilToInt(bounds.width * this.devicePixelRatio);

D.assert(this.image.height == textureHeight);
return true;
});
canvas.save();
try {

D.assert(matrix != null);
this.picture = picture;
this.matrix = new Matrix3(matrix);
var x = this.matrix[2] * devicePixelRatio;
var y = this.matrix[5] * devicePixelRatio;
this.matrix[2] = (x - (int) x) / devicePixelRatio; // x
this.matrix[5] = (y - (int) y) / devicePixelRatio; // y
D.assert(this.matrix[2] == 0);
D.assert(this.matrix[5] == 0);
D.assert(() => {
var x = this.matrix[2] * devicePixelRatio;
var y = this.matrix[5] * devicePixelRatio;
this.matrix[2] = (x - (int) x) / devicePixelRatio; // x
this.matrix[5] = (y - (int) y) / devicePixelRatio; // y
D.assert(Mathf.Abs(this.matrix[2]) <= 1e-5);
D.assert(Mathf.Abs(this.matrix[5]) <= 1e-5);
return true;
});
this.matrix[2] = 0.0f;
this.matrix[5] = 0.0f;
this.devicePixelRatio = devicePixelRatio;
}

RasterCacheResult _rasterizePicture(Picture picture, Matrix3 transform, float devicePixelRatio,
MeshPool meshPool) {
var bounds = transform.mapRect(picture.paintBounds);
var bounds = transform.mapRect(picture.paintBounds).roundOut(devicePixelRatio);
var desc = new RenderTextureDescriptor(
Mathf.CeilToInt((bounds.width * devicePixelRatio)),

3
Runtime/foundation/basic_types.cs


}
public static string toStringList<T>(this IList<T> it) {
if (it == null) {
return null;
}
return "{ " + string.Join(", ", it.Select(item => item.ToString())) + " }";
}
}

38
Runtime/foundation/debug.cs


public static class D {
public static void logError(string message, Exception ex = null) {
Debug.LogException(new ReportError(message, ex));
Debug.LogException(new AssertionError(message, ex));
}
public static bool debugEnabled {
get {
#if UIWidgets_DEBUG
return true;
#else
return false;
#endif
}
[Conditional("UIWidgets_DEBUG")]
public static void assert(Func<bool> result, string message = null) {
if (!result()) {

[Serializable]
public class AssertionError : Exception {
readonly Exception innerException;
public override string StackTrace {
get {
var stackTrace = base.StackTrace;
var lines = stackTrace.Split('\n');
var strippedLines = lines.Skip(1);
return string.Join("\n", strippedLines);
}
}
}
public class ReportError : Exception {
Exception ex;
public ReportError(string message, Exception ex = null) : base(message) {
this.ex = ex;
public AssertionError(string message, Exception innerException = null) : base(message) {
this.innerException = innerException;
if (this.ex != null) {
return this.ex.StackTrace;
if (this.innerException != null) {
return this.innerException.StackTrace;
}
var stackTrace = base.StackTrace;

return string.Join("\n", strippedLines);
}
}
}
}

31
Runtime/foundation/node.mixin.gen.cs


using Unity.UIWidgets.async;
namespace Unity.UIWidgets.foundation {
public class AbstractNode {
public class AbstractNode {
public int depth {
get { return this._depth; }
}

while (node.parent != null) {
node = node.parent;
}
D.assert(node != child); // indicates we are about to create a cycle
return true;
});

}
public class AbstractNodeMixinDiagnosticableTree : DiagnosticableTree {
public class AbstractNodeMixinDiagnosticableTree : DiagnosticableTree {
public int depth {
get { return this._depth; }
}

while (node.parent != null) {
node = node.parent;
}
D.assert(node != child); // indicates we are about to create a cycle
return true;
});

}
public abstract class CanonicalMixinDiagnosticableTree : DiagnosticableTree {
public abstract class CanonicalMixinDiagnosticableTree : DiagnosticableTree {
_DependencyList _dependencyList;
_DependencyList _getDependencyList() {

return this._dependencyList;
}
CanonicalMixinDiagnosticableTree _canonical;
CanonicalMixinDiagnosticableTree _getCanonical() {

}
}
}
public bool alwaysUpdate { get; set; } = true; // if canonicalEquals should not be used.
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {

return false;
}
return ReferenceEquals(this._getCanonical(), ((CanonicalMixinDiagnosticableTree) obj)._getCanonical());
if (this.alwaysUpdate) {
return ReferenceEquals(this, obj);
} else {
return ReferenceEquals(this._getCanonical(), ((CanonicalMixinDiagnosticableTree) obj)._getCanonical());
}
}

8
Runtime/foundation/node.mixin.njk


static readonly Dictionary<_DependencyList, WeakReference> _canonicalObjects =
new Dictionary<_DependencyList, WeakReference>();
public bool alwaysUpdate { get; set; } // if canonicalEquals should not be used.
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;

return false;
}
return ReferenceEquals(this._getCanonical(), ((CanonicalMixin{{with}}) obj)._getCanonical());
if (this.alwaysUpdate) {
return ReferenceEquals(this, obj);
} else {
return ReferenceEquals(this._getCanonical(), ((CanonicalMixin{{with}}) obj)._getCanonical());
}
}
public override int GetHashCode() {

24
Runtime/gestures/monodrag.cs


});
}
this.invokeCallback<object>("onEnd", () => {
this.onEnd(new DragEndDetails(
velocity: Velocity.zero,
primaryVelocity: 0.0f
));
return null;
}, debugReport: () => { return "Pointer scroll end"; }
);
this._state = _DragState.ready;
this.stopTrackingScrollerPointer(evt.pointer);
return;
}

public override void rejectGesture(int pointer) {
this.stopTrackingPointer(pointer);
}
protected override void didStopTrackingLastScrollerPointer(int pointer) {
this._state = _DragState.ready;
this.invokeCallback<object>("onEnd", () => {
this.onEnd(new DragEndDetails(
velocity: Velocity.zero,
primaryVelocity: 0.0f
));
return null;
}, debugReport: () => { return "Pointer scroll end"; }
);
}
protected override void didStopTrackingLastPointer(int pointer) {

9
Runtime/gestures/recognizer.cs


protected abstract void didStopTrackingLastPointer(int pointer);
protected virtual void didStopTrackingLastScrollerPointer(int pointer) {
}
protected virtual void resolve(GestureDisposition disposition) {
var localEntries = new List<GestureArenaEntry>(this._entries.Values);
this._entries.Clear();

protected void startTrackingScrollerPointer(int pointer) {
GestureBinding.instance.pointerRouter.addRoute(pointer, this.handleEvent);
}
protected void stopTrackingScrollerPointer(int pointer) {
if (this._trackedPointers.isEmpty()) {
this.didStopTrackingLastScrollerPointer(pointer);
}
}
protected void startTrackingPointer(int pointer) {

30
Runtime/material/arc.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;

namespace Unity.UIWidgets.material {
static class ArcUtils {
public const float _kOnAxisDelta = 2.0f;
public static readonly List<_Diagonal> _allDiagonals = new List<_Diagonal> {
new _Diagonal(_CornerId.topLeft, _CornerId.bottomRight),
new _Diagonal(_CornerId.bottomRight, _CornerId.topLeft),
new _Diagonal(_CornerId.topRight, _CornerId.bottomLeft),
new _Diagonal(_CornerId.bottomLeft, _CornerId.topRight)
};
public delegate float _KeyFunc<T>(T input);
public static T _maxBy<T>(List<T> input, _KeyFunc<T> keyFunc) {
T maxValue = default(T);
float? maxKey = null;
foreach (T value in input) {
float key = keyFunc(value);
if (maxKey == null || key > maxKey) {
maxValue = value;
maxKey = key;
}
}
return maxValue;
}
}
public class MaterialPointArcTween : Tween<Offset> {
public MaterialPointArcTween(
Offset begin = null,

3
Runtime/material/button.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;

onHighlightChanged: this._handleHighlightChanged,
splashColor: this.widget.splashColor,
highlightColor: this.widget.highlightColor,
onTap: () => {
onTap: this.widget.onPressed == null ? (GestureTapCallback) null : () => {
if (this.widget.onPressed != null) {
this.widget.onPressed();
}

69
Runtime/material/button_theme.cs


this.data = data;
}
public static ButtonTheme fromButtonThemeData(
Key key = null,
ButtonThemeData data = null,
Widget child = null) {
return new ButtonTheme(key, data, child);
}
public static ButtonTheme bar(
Key key = null,
ButtonTextTheme textTheme = ButtonTextTheme.accent,
float minWidth = 64.0f,
float height = 36.0f,
EdgeInsets padding = null,
ShapeBorder shape = null,
bool alignedDropdown = false,
Color buttonColor = null,
Color disabledColor = null,
Color highlightColor = null,
Color splashColor = null,
ColorScheme colorScheme = null,
Widget child = null,
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded
) {
D.assert(minWidth >= 0.0);
D.assert(height >= 0.0);
return new ButtonTheme(key, new ButtonThemeData(
textTheme: textTheme,
minWidth: minWidth,
height: height,
padding: padding ?? EdgeInsets.symmetric(horizontal: 8.0f),
shape: shape,
alignedDropdown: alignedDropdown,
layoutBehavior: layoutBehavior,
buttonColor: buttonColor,
disabledColor: disabledColor,
highlightColor: highlightColor,
splashColor: splashColor,
colorScheme: colorScheme
), child);
}
public readonly ButtonThemeData data;
public static ButtonThemeData of(BuildContext context) {

}
public class ButtonThemeData : Diagnosticable {
public class ButtonThemeData : Diagnosticable, IEquatable<ButtonThemeData> {
public ButtonThemeData(
ButtonTextTheme textTheme = ButtonTextTheme.normal,
float minWidth = 88.0f,

}
Color getDisabledTextColor(MaterialButton button) {
public Color getDisabledTextColor(MaterialButton button) {
if (button.disabledTextColor != null) {
return button.disabledTextColor;
}

return fillColor;
}
//todo:xingwei.zhu: uncomment these when OutlineButton are ready
if (button is FlatButton /* || button is OutlineButton*/) {
if (button is FlatButton || button is OutlineButton) {
return null;
}

return Colors.white;
}
//todo:xingwei.zhu: uncomment these when OutlineButton are ready
if (button is FlatButton /* || button is OutlineButton*/) {
if (button is FlatButton || button is OutlineButton) {
return this.colorScheme.primary;
}

return button.splashColor;
}
//todo:xingwei.zhu: uncomment these when OutlineButton is ready
if (this._splashColor != null && (button is RaisedButton /* || button is OutlineButton*/)) {
if (this._splashColor != null && (button is RaisedButton || button is OutlineButton)) {
return this._splashColor;
}

return 0.0f;
}
//todo:xingwei.zhu: uncomment these when OutlineButton are ready
// if (button is OutlineButton)
// return 2.0;
if (button is OutlineButton) {
return 2.0f;
}
return 8.0f;
}

hashCode = (hashCode * 397) ^ this.padding.GetHashCode();
hashCode = (hashCode * 397) ^ this.shape.GetHashCode();
hashCode = (hashCode * 397) ^ this.alignedDropdown.GetHashCode();
hashCode = (hashCode * 397) ^ this._buttonColor.GetHashCode();
hashCode = (hashCode * 397) ^ this._disabledColor.GetHashCode();
hashCode = (hashCode * 397) ^ this._highlightColor.GetHashCode();
hashCode = (hashCode * 397) ^ this._splashColor.GetHashCode();
hashCode = (hashCode * 397) ^ (this._buttonColor != null ? this._buttonColor.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this._disabledColor != null ? this._disabledColor.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this._highlightColor != null ? this._highlightColor.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this._splashColor != null ? this._splashColor.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.colorScheme.GetHashCode();
hashCode = (hashCode * 397) ^ this._materialTapTargetSize.GetHashCode();
return hashCode;

3
Runtime/material/color_scheme.cs


using System;
public class ColorScheme : Diagnosticable {
public class ColorScheme : Diagnosticable, IEquatable<ColorScheme> {
public ColorScheme(
Color primary,
Color primaryVariant,

10
Runtime/material/constants.cs


namespace Unity.UIWidgets.material {
public static class Constants {
public static readonly float kToolbarHeight = 56.0f;
public const float kToolbarHeight = 56.0f;
public static readonly float kBottomNavigationBarHeight = 56.0f;
public const float kBottomNavigationBarHeight = 56.0f;
public static readonly float kTextTabBarHeight = 48.0f;
public const float kTextTabBarHeight = 48.0f;
public static readonly float kRadialReactionRadius = 20.0f;
public const float kRadialReactionRadius = 20.0f;
public static readonly int kRadialReactionAlpha = 0x1F;
public const int kRadialReactionAlpha = 0x1F;
public static readonly TimeSpan kTabScrollDuration = new TimeSpan(0, 0, 0, 0, 300);

53
Runtime/material/debug.cs


using System.Collections.Generic;
using System.Text;
public static class MaterialDebug {
public static class MaterialD {
public static bool debugCheckHasMaterial(BuildContext context) {
D.assert(() => {
if (!(context.widget is Material) && context.ancestorWidgetOfExactType(typeof(Material)) == null) {

message += "In material design, most widgets are conceptually \"printed\" on " +
"a sheet of material. In Flutter\'s material library, that " +
"a sheet of material. In UIWidgets\'s material library, that " +
"material is represented by the Material widget. It is the " +
"Material widget that renders ink splashes, for instance. " +
"Because of this, many material library widgets require that " +

if (ancestors.isNotEmpty()) {
message += "The ancestors of this widget were:";
foreach (Widget ancestor in ancestors) {
message += "\n $ancestor";
message += "\n " + ancestor;
}
else {
} else {
message += "This widget is the root of the tree, so it has no " +
"ancestors, let alone a \"Material\" ancestor.";
}

return true;
});
return true;
}
public static bool debugCheckHasMaterialLocalizations(BuildContext context) {
D.assert(() => {
if (Localizations.of<MaterialLocalizations>(context, typeof(MaterialLocalizations)) == null) {
StringBuilder message = new StringBuilder();
message.AppendLine("No MaterialLocalizations found.");
message.AppendLine(
context.widget.GetType() + " widgets require MaterialLocalizations " +
"to be provided by a Localizations widget ancestor.");
message.AppendLine(
"Localizations are used to generate many different messages, labels," +
"and abbreviations which are used by the material library. ");
message.AppendLine(
"To introduce a MaterialLocalizations, either use a " +
" MaterialApp at the root of your application to include them " +
"automatically, or add a Localization widget with a " +
"MaterialLocalizations delegate.");
message.AppendLine(
"The specific widget that could not find a MaterialLocalizations ancestor was:"
);
message.AppendLine(" " + context.widget);
List<Widget> ancestors = new List<Widget>();
context.visitAncestorElements((Element element) => {
ancestors.Add(element.widget);
return true;
});
if (ancestors.isNotEmpty()) {
message.Append("The ancestors of this widget were:");
foreach (Widget ancestor in ancestors) {
message.Append("\n " + ancestor);
}
} else {
message.AppendLine(
"This widget is the root of the tree, so it has no " +
"ancestors, let alone a \"Localizations\" ancestor."
);
}
throw new UIWidgetsError(message.ToString());
}
return true;
});
return true;

8
Runtime/material/drawer.cs


using UnityEngine;
namespace Unity.UIWidgets.material {
static class DrawerUtils {
public const float _kWidth = 304.0f;
public const float _kEdgeDragWidth = 20.0f;
public const float _kMinFlingVelocity = 365.0f;
public static readonly TimeSpan _kBaseSettleDuration = new TimeSpan(0, 0, 0, 0, 246);
}
public enum DrawerAlignment {
start,
end

7
Runtime/material/drawer_header.cs


using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.material {
static class DrawerHeaderUtils {
public const float _kDrawerHeaderHeight = 160.0f + 1.0f;
}
public class DrawerHeader : StatelessWidget {
public DrawerHeader(
Key key = null,

public override Widget build(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
ThemeData theme = Theme.of(context);
float statusBarHeight = MediaQuery.of(context).padding.top;
return new Container(

2
Runtime/material/expand_icon.cs


public override Widget build(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
ThemeData theme = Theme.of(context);
return new IconButton(
padding: this.widget.padding,

6
Runtime/material/expansion_panel.cs


using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.material {
static class ExpansionPanelUtils {
public const float _kPanelHeaderCollapsedHeight = 48.0f;
public const float _kPanelHeaderExpandedHeight = 64.0f;
}
class _SaltedKey<S, V> : LocalKey {
public _SaltedKey(
S salt,

5
Runtime/material/expansion_tile.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;

using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.material {
static class ExpansionTileUtils {
public static readonly TimeSpan _kExpand = new TimeSpan(0, 0, 0, 0, 200);
}
public class ExpansionTile : StatefulWidget {
public ExpansionTile(
Key key = null,

8
Runtime/material/icon_button.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;

using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.material {
static class IconButtonUtils {
public const float _kMinButtonSize = 48.0f;
}
public class IconButton : StatelessWidget {
public IconButton(
Key key = null,

public readonly string tooltip;
public override Widget build(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
Color currentColor;
if (this.onPressed != null) {
currentColor = this.color;

998
Runtime/material/icons.cs
文件差异内容过多而无法显示
查看文件

2
Runtime/material/ink_decoration.cs


}
public override Widget build(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
Widget result = new LayoutBuilder(
builder: this._build
);

5
Runtime/material/ink_highlight.cs


using System;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;

namespace Unity.UIWidgets.material {
static class InkHighlightUtils {
public static readonly TimeSpan _kHighlightFadeDuration = new TimeSpan(0, 0, 0, 0, 200);
}
public class InkHighlight : InteractiveInkFeature {
public InkHighlight(
MaterialInkController controller = null,

43
Runtime/material/ink_ripple.cs


using System;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
static class InkRippleUtils {
public static readonly TimeSpan _kUnconfirmedRippleDuration = new TimeSpan(0, 0, 1);
public static readonly TimeSpan _kFadeInDuration = new TimeSpan(0, 0, 0, 0, 75);
public static readonly TimeSpan _kRadiusDuration = new TimeSpan(0, 0, 0, 0, 225);
public static readonly TimeSpan _kFadeOutDuration = new TimeSpan(0, 0, 0, 0, 375);
public static readonly TimeSpan _kCancelDuration = new TimeSpan(0, 0, 0, 0, 75);
public const float _kFadeOutIntervalStart = 225.0f / 375.0f;
public static RectCallback _getClipCallback(RenderBox referenceBox, bool containedInkWell,
RectCallback rectCallback) {
if (rectCallback != null) {
D.assert(containedInkWell);
return rectCallback;
}
if (containedInkWell) {
return () => Offset.zero & referenceBox.size;
}
return null;
}
public static float _getTargetRadius(RenderBox referenceBox, bool containedInkWell, RectCallback rectCallback,
Offset position) {
Size size = rectCallback != null ? rectCallback().size : referenceBox.size;
float d1 = size.bottomRight(Offset.zero).distance;
float d2 = (size.topRight(Offset.zero) - size.bottomLeft(Offset.zero)).distance;
return (Mathf.Max(d1, d2) / 2.0f);
}
}
public class _InkRippleFactory : InteractiveInkFeatureFactory {
public _InkRippleFactory() {
}

}
}
//todo:xingwei.zhu: remove this condition when drawCircle bug fixed (when radius.value == 0)
if (this._radius.value != 0) {
canvas.drawCircle(center, this._radius.value, paint);
}
canvas.drawCircle(center, this._radius.value, paint);
canvas.restore();
}
}

52
Runtime/material/ink_splash.cs


using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
static class InkSplashUtils {
public static readonly TimeSpan _kUnconfirmedSplashDuration = new TimeSpan(0, 0, 0, 1, 0);
public static readonly TimeSpan _kSplashFadeDuration = new TimeSpan(0, 0, 0, 0, 200);
public const float _kSplashInitialSize = 0.0f;
public const float _kSplashConfirmedVelocity = 1.0f;
public static RectCallback _getClipCallback(RenderBox referenceBox, bool containedInkWell,
RectCallback rectCallback) {
if (rectCallback != null) {
D.assert(containedInkWell);
return rectCallback;
}
if (containedInkWell) {
return () => Offset.zero & referenceBox.size;
}
return null;
}
public static float _getTargetRadius(RenderBox referenceBox, bool containedInkWell, RectCallback rectCallback,
Offset position) {
if (containedInkWell) {
Size size = rectCallback != null ? rectCallback().size : referenceBox.size;
return _getSplashRadiusForPositionInSize(size, position);
}
return Material.defaultSplashRadius;
}
static float _getSplashRadiusForPositionInSize(Size bounds, Offset position) {
float d1 = (position - bounds.topLeft(Offset.zero)).distance;
float d2 = (position - bounds.topRight(Offset.zero)).distance;
float d3 = (position - bounds.bottomLeft(Offset.zero)).distance;
float d4 = (position - bounds.bottomRight(Offset.zero)).distance;
return Mathf.Max(Mathf.Max(d1, d2), Mathf.Max(d3, d4)).ceil();
}
}
public class _InkSplashFactory : InteractiveInkFeatureFactory {
public _InkSplashFactory() {
}

}
}
//todo:xingwei.zhu: remove this condition when drawCircle bug fixed (when radius.value == 0)
if (this._radius.value != 0) {
canvas.drawCircle(center, this._radius.value, paint);
}
canvas.drawCircle(center, this._radius.value, paint);
canvas.restore();
}
}

3
Runtime/material/ink_well.cs


public virtual bool debugCheckContext(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
return true;
}

},
onHighlightChanged: onHighlightChanged,
containedInkWell: true,
highlightShape: BoxShape.rectangle,
highlightColor: highlightColor,
splashColor: splashColor,
splashFactory: splashFactory,

7
Runtime/material/list_tile.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;

}
public override Widget build(BuildContext context) {
D.assert(MaterialDebug.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterial(context));
ThemeData theme = Theme.of(context);
ListTileTheme tileTheme = ListTileTheme.of(context);

}
void _mountChild(Widget widget, _ListTileSlot slot) {
Element oldChild = this.slotToChild[slot];
Element oldChild = this.slotToChild.getOrDefault(slot);
Element newChild = this.updateChild(oldChild, widget, slot);
if (oldChild != null) {
this.slotToChild.Remove(slot);

}
void _updateChild(Widget widget, _ListTileSlot slot) {
Element oldChild = this.slotToChild[slot];
Element oldChild = this.slotToChild.getOrDefault(slot);
Element newChild = this.updateChild(oldChild, widget, slot);
if (oldChild != null) {
this.childToSlot.Remove(oldChild);

14
Runtime/material/material.cs


using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.material {
static class MaterialConstantsUtils {
public static readonly Dictionary<MaterialType, BorderRadius> kMaterialEdges =
new Dictionary<MaterialType, BorderRadius> {
{MaterialType.canvas, null},
{MaterialType.card, BorderRadius.circular(2.0f)},
{MaterialType.circle, null},
{MaterialType.button, BorderRadius.circular(2.0f)},
{MaterialType.transparency, null}
};
}
public delegate Rect RectCallback();
public enum MaterialType {

ColorTween _shadowColor;
ShapeBorderTween _border;
protected override void forEachTween(ITweenVisitor visitor) {
protected override void forEachTween(TweenVisitor visitor) {
this._elevation = (FloatTween) visitor.visit(this, this._elevation, this.widget.elevation,
(float value) => new FloatTween(begin: value, end: value));
this._shadowColor = (ColorTween) visitor.visit(this, this._shadowColor, this.widget.shadowColor,

10
Runtime/material/scrollbar.cs


using System;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;

namespace Unity.UIWidgets.material {
static class ScrollbarUtils {
public static readonly TimeSpan _kScrollbarFadeDuration = TimeSpan.FromMilliseconds(300);
public static readonly TimeSpan _kScrollbarTimeToFade = TimeSpan.FromMilliseconds(600);
public const float _kScrollbarThickness = 6.0f;
}
public class Scrollbar : StatefulWidget {
public Scrollbar(
Key key = null,

108
Runtime/material/text_selection.cs


using Rect = Unity.UIWidgets.ui.Rect;
using Transform = Unity.UIWidgets.widgets.Transform;
// todo using material components: FlatButton & Material ...
}
static class _TextSelectionUtils {
public _TextSelectionToolbar(Key key = null, Action handleCut = null,
Action handleCopy = null, Action handlePaste = null, Action handleSelectAll = null) : base(key: key) {
public _TextSelectionToolbar(Key key = null, VoidCallback handleCut = null,
VoidCallback handleCopy = null, VoidCallback handlePaste = null, VoidCallback handleSelectAll = null) : base(key: key) {
this.handleCut = handleCut;
this.handleCopy = handleCopy;
this.handlePaste = handlePaste;

public readonly Action handleCut;
public readonly Action handleCopy;
public readonly Action handlePaste;
public readonly Action handleSelectAll;
public readonly VoidCallback handleCut;
public readonly VoidCallback handleCopy;
public readonly VoidCallback handlePaste;
public readonly VoidCallback handleSelectAll;
MaterialLocalizations localizations = MaterialLocalizations.of(context);
items.Add(new _TempButton(onPressed: () => this.handleCut(), child: new Text("Cut")));
items.Add(new FlatButton(child: new Text(localizations.cutButtonLabel), onPressed: this.handleCut));
items.Add(new _TempButton(onPressed: () => this.handleCopy(), child: new Text("Copy")));
items.Add(new FlatButton(child: new Text(localizations.copyButtonLabel), onPressed: this.handleCopy));
items.Add(new _TempButton(onPressed: () => this.handlePaste(), child: new Text("Past")));
items.Add(new FlatButton(child: new Text(localizations.pasteButtonLabel), onPressed: this.handlePaste));
items.Add(new _TempButton(onPressed: () => this.handleSelectAll(), child: new Text("Select All")));
items.Add(new FlatButton(child: new Text(localizations.selectAllButtonLabel),
onPressed: this.handleSelectAll));
return new Container(
color: new Color(0xFFEFEFEF),
height: 44.0f, child: new Row(mainAxisSize: MainAxisSize.min, children: items));
return new Material(
elevation: 1.0f,
child: new Container(
color: new Color(0xFFEFEFEF),
height: 44.0f, child: new Row(mainAxisSize: MainAxisSize.min, children: items))
);
}
}

float x = globalPosition.dx - childSize.width / 2.0f;
float y = globalPosition.dy - childSize.height;
if (x < _TextSelectionUtils._kToolbarScreenPadding) {
x = _TextSelectionUtils._kToolbarScreenPadding;
if (x < MaterialUtils._kToolbarScreenPadding) {
x = MaterialUtils._kToolbarScreenPadding;
else if (x + childSize.width > this.screenSize.width - _TextSelectionUtils._kToolbarScreenPadding) {
x = this.screenSize.width - childSize.width - _TextSelectionUtils._kToolbarScreenPadding;
else if (x + childSize.width > this.screenSize.width - MaterialUtils._kToolbarScreenPadding) {
x = this.screenSize.width - childSize.width - MaterialUtils._kToolbarScreenPadding;
if (y < _TextSelectionUtils._kToolbarScreenPadding) {
y = _TextSelectionUtils._kToolbarScreenPadding;
if (y < MaterialUtils._kToolbarScreenPadding) {
y = MaterialUtils._kToolbarScreenPadding;
else if (y + childSize.height > this.screenSize.height - _TextSelectionUtils._kToolbarScreenPadding) {
y = this.screenSize.height - childSize.height - _TextSelectionUtils._kToolbarScreenPadding;
else if (y + childSize.height > this.screenSize.height - MaterialUtils._kToolbarScreenPadding) {
y = this.screenSize.height - childSize.height - MaterialUtils._kToolbarScreenPadding;
}
return new Offset(x, y);

class _MaterialTextSelectionControls : TextSelectionControls {
public override Size handleSize {
get {
return new Size(_TextSelectionUtils._kHandleSize,
_TextSelectionUtils._kHandleSize);
return new Size(MaterialUtils._kHandleSize,
MaterialUtils._kHandleSize);
}
}

child: new _TextSelectionToolbar(
handleCut: this.canCut(selectionDelegate)
? () => this.handleCut(selectionDelegate)
: (Action) null,
: (VoidCallback) null,
: (Action) null,
: (VoidCallback) null,
: (Action) null,
: (VoidCallback) null,
: (Action) null
: (VoidCallback) null
)
)
);

Widget handle = new Padding(
padding: EdgeInsets.only(right: 26.0f, bottom: 26.0f),
child: new SizedBox(
width: 20,
height: 20,
width: MaterialUtils._kHandleSize,
height: MaterialUtils._kHandleSize,
color: new Color(0xFFFF0000)
color: Theme.of(context).textSelectionHandleColor
)
)
)

}
return null;
}
}
public class _TempButton : StatelessWidget {
public _TempButton(
Key key = null,
GestureTapCallback onPressed = null,
EdgeInsets padding = null,
Color backgroundColor = null,
Widget child = null
) : base(key: key) {
this.onPressed = onPressed;
this.padding = padding ?? EdgeInsets.all(8.0f);
this.backgroundColor = backgroundColor ?? new Color(0);
this.child = child;
}
public readonly GestureTapCallback onPressed;
public readonly EdgeInsets padding;
public readonly Widget child;
public readonly Color backgroundColor;
public override Widget build(BuildContext context) {
return new GestureDetector(
onTap: this.onPressed,
child: new Container(
padding: this.padding,
color: this.backgroundColor,
child: this.child
)
);
}
}
}

3
Runtime/material/text_theme.cs


using System;
public class TextTheme : Diagnosticable {
public class TextTheme : Diagnosticable, IEquatable<TextTheme> {
public TextTheme(
TextStyle display4 = null,
TextStyle display3 = null,

12
Runtime/material/theme.cs


using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.material {
public static class ThemeUtils {
public static readonly TimeSpan kThemeAnimationDuration = new TimeSpan(0, 0, 0, 0, 200);
}
public class Theme : StatelessWidget {
public Theme(
Key key = null,

return inheritedTheme.theme.data;
}
//todo:xingwei.zhu: material Localizations
return inheritedTheme?.theme?.data ?? _kFallbackTheme;
MaterialLocalizations localizations = MaterialLocalizations.of(context);
ScriptCategory category = ScriptCategory.englishLike;
ThemeData theme = inheritedTheme?.theme?.data ?? _kFallbackTheme;
return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
}
public override Widget build(BuildContext context) {

class _AnimatedThemeState : AnimatedWidgetBaseState<AnimatedTheme> {
ThemeDataTween _data;
protected override void forEachTween(ITweenVisitor visitor) {
protected override void forEachTween(TweenVisitor visitor) {
this._data = (ThemeDataTween) visitor.visit(this, this._data, this.widget.data,
(ThemeData value) => new ThemeDataTween(begin: value));
}

359
Runtime/material/theme_data.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.ui;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
static class ThemeDataUtils {
public static readonly Color _kLightThemeHighlightColor = new Color(0x66BCBCBC);
public static readonly Color _kLightThemeSplashColor = new Color(0x66C8C8C8);
public static readonly Color _kDarkThemeHighlightColor = new Color(0x40CCCCCC);
public static readonly Color _kDarkThemeSplashColor = new Color(0x40CCCCCC);
}
public enum MaterialTapTargetSize {
padded,

public class ThemeData : Diagnosticable {
public class ThemeData : Diagnosticable, IEquatable<ThemeData> {
public ThemeData(
Brightness? brightness = null,
MaterialColor primarySwatch = null,

TextTheme textTheme = null,
TextTheme primaryTextTheme = null,
TextTheme accentTextTheme = null,
InputDecorationTheme inputDecorationTheme = null,
TabBarTheme tabBarTheme = null,
RuntimePlatform? platform = null,
PageTransitionsTheme pageTransitionsTheme = null,
DialogTheme dialogTheme = null,
Typography typography = null
) {
brightness = brightness ?? Brightness.light;

indicatorColor = indicatorColor ?? (accentColor == primaryColor ? Colors.white : accentColor);
hintColor = hintColor ?? (isDark ? new Color(0x80FFFFFF) : new Color(0x8A000000));
errorColor = errorColor ?? Colors.red[700];
inputDecorationTheme = inputDecorationTheme ?? new InputDecorationTheme();
pageTransitionsTheme = pageTransitionsTheme ?? new PageTransitionsTheme();
primaryIconTheme = primaryIconTheme ??
(primaryIsDark
? new IconThemeData(color: Colors.white)

: new IconThemeData(color: Colors.black));
iconTheme = iconTheme ??
(isDark ? new IconThemeData(color: Colors.white) : new IconThemeData(color: Colors.black87));
platform = platform ?? Application.platform;
typography = typography ?? new Typography();
TextTheme defaultTextTheme = isDark ? typography.white : typography.black;
textTheme = defaultTextTheme.merge(textTheme);

? ThemeDataUtils._kDarkThemeSplashColor
: ThemeDataUtils._kLightThemeSplashColor);
tabBarTheme = tabBarTheme ?? new TabBarTheme();
dialogTheme = dialogTheme ?? new DialogTheme();
D.assert(brightness != null);
D.assert(primaryColor != null);
D.assert(primaryColorBrightness != null);

D.assert(primaryIconTheme != null);
D.assert(accentIconTheme != null);
D.assert(materialTapTargetSize != null);
D.assert(pageTransitionsTheme != null);
D.assert(tabBarTheme != null);
D.assert(dialogTheme != null);
this.brightness = brightness ?? Brightness.light;
this.primaryColor = primaryColor;

this.textTheme = textTheme;
this.primaryTextTheme = primaryTextTheme;
this.accentTextTheme = accentTextTheme;
this.inputDecorationTheme = inputDecorationTheme;
this.tabBarTheme = tabBarTheme;
this.platform = platform.Value;
this.pageTransitionsTheme = pageTransitionsTheme;
this.dialogTheme = dialogTheme;
Brightness? brightness,
Color primaryColor,
Brightness? primaryColorBrightness,
Color primaryColorLight,
Color primaryColorDark,
Color canvasColor,
Color accentColor,
Brightness? accentColorBrightness,
Color scaffoldBackgroundColor,
Color bottomAppBarColor,
Color cardColor,
Color dividerColor,
Color highlightColor,
Color splashColor,
InteractiveInkFeatureFactory splashFactory,
Color selectedRowColor,
Color unselectedWidgetColor,
Color disabledColor,
ButtonThemeData buttonTheme,
Color buttonColor,
Color secondaryHeaderColor,
Color textSelectionColor,
Color cursorColor,
Color textSelectionHandleColor,
Color backgroundColor,
Color dialogBackgroundColor,
Color indicatorColor,
Color hintColor,
Color errorColor,
Color toggleableActiveColor,
TextTheme textTheme,
TextTheme primaryTextTheme,
TextTheme accentTextTheme,
IconThemeData iconTheme,
IconThemeData primaryIconTheme,
IconThemeData accentIconTheme,
MaterialTapTargetSize? materialTapTargetSize,
ColorScheme colorScheme,
Typography typography
Brightness? brightness = null,
Color primaryColor = null,
Brightness? primaryColorBrightness = null,
Color primaryColorLight = null,
Color primaryColorDark = null,
Color canvasColor = null,
Color accentColor = null,
Brightness? accentColorBrightness = null,
Color scaffoldBackgroundColor = null,
Color bottomAppBarColor = null,
Color cardColor = null,
Color dividerColor = null,
Color highlightColor = null,
Color splashColor = null,
InteractiveInkFeatureFactory splashFactory = null,
Color selectedRowColor = null,
Color unselectedWidgetColor = null,
Color disabledColor = null,
ButtonThemeData buttonTheme = null,
Color buttonColor = null,
Color secondaryHeaderColor = null,
Color textSelectionColor = null,
Color cursorColor = null,
Color textSelectionHandleColor = null,
Color backgroundColor = null,
Color dialogBackgroundColor = null,
Color indicatorColor = null,
Color hintColor = null,
Color errorColor = null,
Color toggleableActiveColor = null,
TextTheme textTheme = null,
TextTheme primaryTextTheme = null,
TextTheme accentTextTheme = null,
InputDecorationTheme inputDecorationTheme = null,
IconThemeData iconTheme = null,
IconThemeData primaryIconTheme = null,
IconThemeData accentIconTheme = null,
TabBarTheme tabBarTheme = null,
RuntimePlatform? platform = null,
MaterialTapTargetSize? materialTapTargetSize = null,
PageTransitionsTheme pageTransitionsTheme = null,
ColorScheme colorScheme = null,
DialogTheme dialogTheme = null,
Typography typography = null
) {
D.assert(brightness != null);
D.assert(primaryColor != null);

D.assert(textTheme != null);
D.assert(primaryTextTheme != null);
D.assert(accentTextTheme != null);
D.assert(inputDecorationTheme != null);
D.assert(platform != null);
D.assert(pageTransitionsTheme != null);
D.assert(tabBarTheme != null);
D.assert(dialogTheme != null);
return new ThemeData(
brightness: brightness,

textTheme: textTheme,
primaryTextTheme: primaryTextTheme,
accentTextTheme: accentTextTheme,
inputDecorationTheme: inputDecorationTheme,
tabBarTheme: tabBarTheme,
platform: platform,
pageTransitionsTheme: pageTransitionsTheme,
dialogTheme: dialogTheme,
typography: typography);
}

public readonly TextTheme accentTextTheme;
public readonly InputDecorationTheme inputDecorationTheme;
public readonly IconThemeData iconTheme;
public readonly IconThemeData primaryIconTheme;

public readonly TabBarTheme tabBarTheme;
public readonly RuntimePlatform platform;
public readonly PageTransitionsTheme pageTransitionsTheme;
public readonly DialogTheme dialogTheme;
Brightness? brightness,
Color primaryColor,
Brightness? primaryColorBrightness,
Color primaryColorLight,
Color primaryColorDark,
Color accentColor,
Brightness? accentColorBrightness,
Color canvasColor,
Color scaffoldBackgroundColor,
Color bottomAppBarColor,
Color cardColor,
Color dividerColor,
Color highlightColor,
Color splashColor,
InteractiveInkFeatureFactory splashFactory,
Color selectedRowColor,
Color unselectedWidgetColor,
Color disabledColor,
ButtonThemeData buttonTheme,
Color buttonColor,
Color secondaryHeaderColor,
Color textSelectionColor,
Color cursorColor,
Color textSelectionHandleColor,
Color backgroundColor,
Color dialogBackgroundColor,
Color indicatorColor,
Color hintColor,
Color errorColor,
Color toggleableActiveColor,
TextTheme textTheme,
TextTheme primaryTextTheme,
TextTheme accentTextTheme,
IconThemeData iconTheme,
IconThemeData primaryIconTheme,
IconThemeData accentIconTheme,
MaterialTapTargetSize? materialTapTargetSize,
ColorScheme colorScheme,
Typography typography
Brightness? brightness = null,
Color primaryColor = null,
Brightness? primaryColorBrightness = null,
Color primaryColorLight = null,
Color primaryColorDark = null,
Color accentColor = null,
Brightness? accentColorBrightness = null,
Color canvasColor = null,
Color scaffoldBackgroundColor = null,
Color bottomAppBarColor = null,
Color cardColor = null,
Color dividerColor = null,
Color highlightColor = null,
Color splashColor = null,
InteractiveInkFeatureFactory splashFactory = null,
Color selectedRowColor = null,
Color unselectedWidgetColor = null,
Color disabledColor = null,
ButtonThemeData buttonTheme = null,
Color buttonColor = null,
Color secondaryHeaderColor = null,
Color textSelectionColor = null,
Color cursorColor = null,
Color textSelectionHandleColor = null,
Color backgroundColor = null,
Color dialogBackgroundColor = null,
Color indicatorColor = null,
Color hintColor = null,
Color errorColor = null,
Color toggleableActiveColor = null,
TextTheme textTheme = null,
TextTheme primaryTextTheme = null,
TextTheme accentTextTheme = null,
InputDecorationTheme inputDecorationTheme = null,
IconThemeData iconTheme = null,
IconThemeData primaryIconTheme = null,
IconThemeData accentIconTheme = null,
TabBarTheme tabBarTheme = null,
RuntimePlatform? platform = null,
MaterialTapTargetSize? materialTapTargetSize = null,
PageTransitionsTheme pageTransitionsTheme = null,
ColorScheme colorScheme = null,
DialogTheme dialogTheme = null,
Typography typography = null
) {
return raw(
brightness: brightness ?? this.brightness,

textTheme: textTheme ?? this.textTheme,
primaryTextTheme: primaryTextTheme ?? this.primaryTextTheme,
accentTextTheme: accentTextTheme ?? this.accentTextTheme,
inputDecorationTheme: this.inputDecorationTheme ?? this.inputDecorationTheme,
tabBarTheme: tabBarTheme ?? this.tabBarTheme,
platform: platform ?? this.platform,
pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme,
dialogTheme: dialogTheme ?? this.dialogTheme,
const int _localizedThemeDataCacheSize = 5;
static readonly _FifoCache<_IdentityThemeDataCacheKey, ThemeData> _localizedThemeDataCache =
new _FifoCache<_IdentityThemeDataCacheKey, ThemeData>(_localizedThemeDataCacheSize);
public static ThemeData localize(ThemeData baseTheme, TextTheme localTextGeometry) {
D.assert(baseTheme != null);
D.assert(localTextGeometry != null);
return _localizedThemeDataCache.putIfAbsent(
new _IdentityThemeDataCacheKey(baseTheme, localTextGeometry),
() => {
return baseTheme.copyWith(
primaryTextTheme: localTextGeometry.merge(baseTheme.primaryTextTheme),
accentTextTheme: localTextGeometry.merge(baseTheme.accentTextTheme),
textTheme: localTextGeometry.merge(baseTheme.textTheme)
);
});
}
public static Brightness estimateBrightnessForColor(Color color) {
float relativeLuminance = color.computeLuminance();

textTheme: TextTheme.lerp(a.textTheme, b.textTheme, t),
primaryTextTheme: TextTheme.lerp(a.primaryTextTheme, b.primaryTextTheme, t),
accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t),
inputDecorationTheme: t < 0.5f ? a.inputDecorationTheme : b.inputDecorationTheme,
tabBarTheme: TabBarTheme.lerp(a.tabBarTheme, b.tabBarTheme, t),
platform: t < 0.5 ? a.platform : b.platform,
pageTransitionsTheme: t < 0.5 ? a.pageTransitionsTheme : b.pageTransitionsTheme,
dialogTheme: DialogTheme.lerp(a.dialogTheme, b.dialogTheme, t),
typography: Typography.lerp(a.typography, b.typography, t)
);
}

other.textTheme == this.textTheme &&
other.primaryTextTheme == this.primaryTextTheme &&
other.accentTextTheme == this.accentTextTheme &&
other.inputDecorationTheme == this.inputDecorationTheme &&
other.tabBarTheme == this.tabBarTheme &&
other.platform == this.platform &&
other.pageTransitionsTheme == this.pageTransitionsTheme &&
other.dialogTheme == this.dialogTheme &&
other.typography == this.typography;
}

hashCode = (hashCode * 397) ^ this.textTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.primaryTextTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.accentTextTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.inputDecorationTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.tabBarTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.platform.GetHashCode();
hashCode = (hashCode * 397) ^ this.pageTransitionsTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.dialogTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.typography.GetHashCode();
return hashCode;
}

base.debugFillProperties(properties);
ThemeData defaultData = fallback();
properties.add(new EnumProperty<RuntimePlatform>("platform", this.platform,
defaultValue: Application.platform));
properties.add(new EnumProperty<Brightness>("brightness", this.brightness,
defaultValue: defaultData.brightness));
properties.add(new DiagnosticsProperty<Color>("primaryColor", this.primaryColor,

properties.add(new DiagnosticsProperty<TextTheme>("textTheme", this.textTheme));
properties.add(new DiagnosticsProperty<TextTheme>("primaryTextTheme", this.primaryTextTheme));
properties.add(new DiagnosticsProperty<TextTheme>("accentTextTheme", this.accentTextTheme));
properties.add(new DiagnosticsProperty<InputDecorationTheme>("inputDecorationTheme", this.inputDecorationTheme));
properties.add(new DiagnosticsProperty<TabBarTheme>("tabBarTheme", this.tabBarTheme));
properties.add(
new DiagnosticsProperty<PageTransitionsTheme>("pageTransitionsTheme", this.pageTransitionsTheme));
properties.add(new DiagnosticsProperty<DialogTheme>("dialogTheme", this.dialogTheme,
defaultValue: defaultData.dialogTheme));
}
}
class _IdentityThemeDataCacheKey : IEquatable<_IdentityThemeDataCacheKey> {
public _IdentityThemeDataCacheKey(
ThemeData baseTheme,
TextTheme localTextGeometry) {
this.baseTheme = baseTheme;
this.localTextGeometry = localTextGeometry;
}
public readonly ThemeData baseTheme;
public readonly TextTheme localTextGeometry;
public bool Equals(_IdentityThemeDataCacheKey other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.baseTheme == other.baseTheme &&
this.localTextGeometry == other.localTextGeometry;
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((_IdentityThemeDataCacheKey) obj);
}
public static bool operator ==(_IdentityThemeDataCacheKey left, _IdentityThemeDataCacheKey right) {
return Equals(left, right);
}
public static bool operator !=(_IdentityThemeDataCacheKey left, _IdentityThemeDataCacheKey right) {
return !Equals(left, right);
}
public override int GetHashCode() {
var hashCode = this.baseTheme.GetHashCode();
hashCode = (hashCode * 397) ^ this.localTextGeometry.GetHashCode();
return hashCode;
}
}
class _FifoCache<K, V> {
public _FifoCache(int maximumSize) {
D.assert(maximumSize > 0);
this._maximumSize = maximumSize;
}
readonly Dictionary<K, V> _cache = new Dictionary<K, V>();
readonly int _maximumSize;
public V putIfAbsent(K key, Func<V> value) {
D.assert(key != null);
D.assert(value != null);
if (this._cache.ContainsKey(key)) {
return this._cache[key];
}
if (this._cache.Count == this._maximumSize) {
this._cache.Remove(this._cache.Keys.First());
}
this._cache[key] = value();
return this._cache[key];
}
}
}

7
Runtime/material/tooltip.cs


using System;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;

using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.material {
static class TooltipUtils {
public static readonly TimeSpan _kFadeDuration = new TimeSpan(0, 0, 0, 0, 200);
public static readonly TimeSpan _kShowDuration = new TimeSpan(0, 0, 0, 0, 1500);
}
public class Tooltip : StatefulWidget {
public Tooltip(
Key key = null,

15
Runtime/painting/image_provider.cs


IEnumerator _loadAssetAsync(AssetBundleImageKey key) {
if (key.bundle == null) {
ResourceRequest request = Resources.LoadAsync(key.name);
yield return request;
yield return request.asset;
if (request.asset) {
yield return request.asset;
} else {
yield return request;
yield return request.asset;
}
yield return request;
yield return request.asset;
if (request.asset) {
yield return request.asset;
} else {
yield return request.asset;
}
}
}
}

41
Runtime/painting/image_resolution.cs


using System;
using System.Collections;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;

public readonly string assetName;
public readonly AssetBundle bundle;
protected override
IPromise<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
protected override IPromise<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
AssetImageConfiguration assetConfig = new AssetImageConfiguration(configuration, this.assetName);
AssetBundleImageKey key;
var cache = AssetBundleCache.instance.get(configuration.bundle);

AssetBundle chosenBundle = this.bundle ? this.bundle : configuration.bundle;
var devicePixelRatio = configuration.devicePixelRatio ?? Window.instance.devicePixelRatio;
var coroutine = Window.instance.startCoroutine(this._loadAssetAsync(chosenBundle, devicePixelRatio));
return coroutine.promise.Then(result => {
D.assert(result != null);
key = (AssetBundleImageKey) result;
cache[assetConfig] = key;
return key;
});
key = this._loadAsset(chosenBundle, devicePixelRatio);
cache[assetConfig] = key;
return Promise<AssetBundleImageKey>.Resolved(key);
IEnumerator _loadAssetAsync(AssetBundle bundle, float devicePixelRatio) {
AssetBundleImageKey _loadAsset(AssetBundle bundle, float devicePixelRatio) {
var upper = devicePixelRatio.ceil();
var upper = Mathf.Min(3, devicePixelRatio.ceil());
ResourceRequest request = Resources.LoadAsync(assetName);
yield return request;
asset = request.asset;
}
else {
AssetBundleRequest request = bundle.LoadAssetAsync(assetName);
yield return request;
asset = request.asset;
asset = Resources.Load(assetName);
} else {
asset = bundle.LoadAsset(assetName);
}
else {
} else {
yield return new AssetBundleImageKey(
return new AssetBundleImageKey(
yield break;
yield return new AssetBundleImageKey(
return new AssetBundleImageKey(
bundle,
this.assetName,
scale: 1.0f

4
Runtime/painting/text_painter.cs


var builder = new ParagraphBuilder(this._createParagraphStyle(TextDirection.ltr)
); // direction doesn't matter, text is just a space
if (this.text != null && this.text.style != null) {
builder.pushStyle(this.text.style);
builder.pushStyle(this.text.style, this.textScaleFactor);
}
builder.addText(" ");

}
Offset _getOffsetFromDownstream(int offset, Rect caretPrototype) {
var nextCodeUnit = this._text.codeUnitAt(offset);
var nextCodeUnit = this._text.codeUnitAt(offset - 1);
if (nextCodeUnit == null) {
return null;
}

41
Runtime/painting/text_span.cs


public readonly List<TextSpan> children;
public readonly GestureRecognizer recognizer;
public TextSpan(string text = "", TextStyle style = null, List<TextSpan> children = null) {
public TextSpan(string text = "", TextStyle style = null, List<TextSpan> children = null,
GestureRecognizer recognizer = null) {
this.recognizer = recognizer;
var hasTyle = this.style != null;
if (hasTyle) {
builder.pushStyle(this.style);
var hasStyle = this.style != null;
if (hasStyle) {
builder.pushStyle(this.style, textScaleFactor);
}
if (!string.IsNullOrEmpty(this.text)) {

}
}
if (hasTyle) {
if (hasStyle) {
builder.pop();
}
}

return true;
}
TextSpan getSpanForPosition(TextPosition position) {
public TextSpan getSpanForPosition(TextPosition position) {
D.assert(this.debugAssertIsValid());
var offset = 0;
var targetOffset = position.offset;
var affinity = position.affinity;

});
return result;
}
public string toPlainText() {
var sb = new StringBuilder();
this.visitTextSpan((span) => {

return result;
}
bool debugAssertIsValid() {
D.assert(() => {
if (!this.visitTextSpan(span => {
if (span.children != null) {
foreach (TextSpan child in span.children) {
if (child == null)
return false;
}
}
return true;
})) {
throw new UIWidgetsError(
"A TextSpan object with a non-null child list should not have any nulls in its child list.\n" +
"The full text in question was:\n" +
this.toStringDeep(prefixLineOne:" "));
}
return true;
});
return true;
}
public RenderComparison compareTo(TextSpan other) {
if (this.Equals(other)) {
return RenderComparison.identical;

unchecked {
var hashCode = (this.style != null ? this.style.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.text != null ? this.text.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.recognizer != null ? this.recognizer.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.childHash());
return hashCode;
}

}
return Equals(this.style, other.style) && string.Equals(this.text, other.text) &&
childEquals(this.children, other.children);
childEquals(this.children, other.children) && this.recognizer == other.recognizer;
}
public static bool operator ==(TextSpan left, TextSpan right) {

56
Runtime/painting/text_style.cs


using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.painting {
public class TextStyle : Diagnosticable, IEquatable<TextStyle>, ParagraphBuilder.ITextStyleProvider {
public class TextStyle : Diagnosticable, IEquatable<TextStyle> {
public readonly FontWeight? fontWeight;
public readonly FontWeight fontWeight;
public readonly FontStyle? fontStyle;
public readonly float? letterSpacing;
public readonly float? wordSpacing;

public TextStyle(bool inherit = true, Color color = null, float? fontSize = null,
FontWeight? fontWeight = null,
FontWeight fontWeight = null,
FontStyle? fontStyle = null, float? letterSpacing = null, float? wordSpacing = null,
TextBaseline? textBaseline = null, float? height = null, Paint background = null,
TextDecoration decoration = null,

this.background = background;
}
public ui.TextStyle getTextStyle(ui.TextStyle currentStyle = null) {
if (currentStyle != null) {
return new ui.TextStyle(
color: this.color ?? currentStyle.color,
fontSize: this.fontSize ?? currentStyle.fontSize,
fontWeight: this.fontWeight ?? currentStyle.fontWeight,
fontStyle: this.fontStyle ?? currentStyle.fontStyle,
letterSpacing: this.letterSpacing ?? currentStyle.letterSpacing,
wordSpacing: this.wordSpacing ?? currentStyle.wordSpacing,
textBaseline: this.textBaseline ?? currentStyle.textBaseline,
height: this.height ?? currentStyle.height,
decoration: this.decoration ?? currentStyle.decoration,
decorationColor: this.decorationColor ?? currentStyle.decorationColor,
fontFamily: this.fontFamily ?? currentStyle.fontFamily,
background: this.background ?? currentStyle.background
);
}
return new ui.TextStyle(
color: this.color,
fontSize: this.fontSize,
fontWeight: this.fontWeight,
fontStyle: this.fontStyle,
letterSpacing: this.letterSpacing,
wordSpacing: this.wordSpacing,
textBaseline: this.textBaseline,
height: this.height,
decoration: this.decoration,
decorationColor: this.decorationColor,
fontFamily: this.fontFamily,
background: this.background
);
}
public RenderComparison compareTo(TextStyle other) {
if (this.inherit != other.inherit || this.fontFamily != other.fontFamily
|| this.fontSize != other.fontSize || this.fontWeight != other.fontWeight

decoration: other.decoration,
decorationColor: other.decorationColor,
decorationStyle: other.decorationStyle,
background: other.background,
debugLabel: mergedDebugLabel
);
}

float? fontSize = null,
FontWeight? fontWeight = null,
FontWeight fontWeight = null,
FontStyle? fontStyle = null,
float? letterSpacing = null,
float? wordSpacing = null,

defaultValue: Diagnostics.kNullDefaultValue));
string weightDescription = "";
if (this.fontWeight != null) {
switch (this.fontWeight) {
case FontWeight.w400:
weightDescription = "400";
break;
case FontWeight.w700:
weightDescription = "700";
break;
}
weightDescription = this.fontWeight.weightValue.ToString();
styles.Add(new DiagnosticsProperty<FontWeight?>(
styles.Add(new DiagnosticsProperty<FontWeight>(
"weight", this.fontWeight,
description: weightDescription,
defaultValue: Diagnostics.kNullDefaultValue

var hashCode = this.inherit.GetHashCode();
hashCode = (hashCode * 397) ^ (this.color != null ? this.color.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontSize.GetHashCode();
hashCode = (hashCode * 397) ^ this.fontWeight.GetHashCode();
hashCode = (hashCode * 397) ^ (this.fontWeight != null ? this.fontWeight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontStyle.GetHashCode();
hashCode = (hashCode * 397) ^ this.letterSpacing.GetHashCode();
hashCode = (hashCode * 397) ^ this.wordSpacing.GetHashCode();

12
Runtime/promise/Promise.cs


/// Handle errors for the promise.
/// </summary>
public IPromise<PromisedT> Catch(Func<Exception, PromisedT> onRejected) {
var resultPromise = new Promise<PromisedT>();
var resultPromise = new Promise<PromisedT>(isSync: true);
resultPromise.WithName(this.Name);
Action<PromisedT> resolveHandler = v => resultPromise.Resolve(v);

// Otherwise there is now way to get the converted value to pass to the resulting promise.
// Argument.NotNull(() => onResolved);
var resultPromise = new Promise<ConvertedT>();
var resultPromise = new Promise<ConvertedT>(isSync: true);
resultPromise.WithName(this.Name);
Action<PromisedT> resolveHandler = v => {

var remainingCount = promisesArray.Length;
var results = new PromisedT[remainingCount];
var progress = new float[remainingCount];
var resultPromise = new Promise<IEnumerable<PromisedT>>();
var resultPromise = new Promise<IEnumerable<PromisedT>>(isSync: true);
resultPromise.WithName("All");
promisesArray.Each((promise, index) => {

);
}
var resultPromise = new Promise<PromisedT>();
var resultPromise = new Promise<PromisedT>(isSync: true);
resultPromise.WithName("Race");
var progress = new float[promisesArray.Length];

public static IPromise<PromisedT> Rejected(Exception ex) {
// Argument.NotNull(() => ex);
var promise = new Promise<PromisedT>();
var promise = new Promise<PromisedT>(isSync: true);
var promise = new Promise<PromisedT>();
var promise = new Promise<PromisedT>(isSync: true);
promise.WithName(this.Name);
this.Then(x => promise.Resolve(x));

11
Runtime/promise/Promise_NonGeneric.cs


// Otherwise there is now way to get the converted value to pass to the resulting promise.
// Argument.NotNull(() => onResolved);
var resultPromise = new Promise<ConvertedT>();
var resultPromise = new Promise<ConvertedT>(isSync: true);
resultPromise.WithName(this.Name);
Action resolveHandler = () => {

public static IPromise Rejected(Exception ex) {
// Argument.NotNull(() => ex);
var promise = new Promise();
var promise = new Promise(isSync: true);
return promise;
}
public static IPromise Delayed(TimeSpan duration) {
var promise = new Promise(isSync: true);
Window.instance.run(duration, () => { promise.Resolve(); });
return promise;
}

3
Runtime/rendering/binding.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.rendering {

}
protected virtual void drawFrame() {
PerformanceUtils.instance.startProfile();
PerformanceUtils.instance.endProfile();
}
public override void hitTest(HitTestResult result, Offset position) {

11
Runtime/rendering/box.cs


});
}
public virtual bool hitTest(HitTestResult result, Offset position) {
public virtual bool hitTest(HitTestResult result, Offset position = null) {
D.assert(position != null);
D.assert(() => {
if (!this.hasSize) {
if (this.debugNeedsLayout) {

// ideographic baseline
float? baselineI = this.getDistanceToBaseline(TextBaseline.ideographic, onlyReal: true);
if (baselineI != null) {
paint.color = new Color(0xFFFFD000);
paint.color = new Color(0xFFFFD000);
path = new Path();
path.moveTo(offset.dx, offset.dy + baselineI.Value);
path.lineTo(offset.dx + this.size.width, offset.dy + baselineI.Value);

// alphabetic baseline
float? baselineA = this.getDistanceToBaseline(TextBaseline.alphabetic, onlyReal: true);
if (baselineA != null) {
paint.color = new Color (0xFF00FF00);
paint.color = new Color(0xFF00FF00);
path = new Path();
path.moveTo(offset.dx, offset.dy + baselineA.Value);
path.lineTo(offset.dx + this.size.width, offset.dy + baselineA.Value);

base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Size>("size", this._size, missingIfNull: true));
}
}
public abstract class ContainerBoxParentData<ChildType> : ContainerParentDataMixinBoxParentData<ChildType>
where ChildType : RenderBox {
}
public abstract class

18
Runtime/rendering/box.mixin.gen.cs


using System;
using UnityEngine;
using UnityEngine;
public float? defaultComputeDistanceToFirstActualBaseline(TextBaseline baseline) {
var child = this.firstChild;
while (child != null) {

candidate += childParentData.offset.dy;
if (result != null) {
result = Mathf.Min(result.Value, candidate.Value);
}
else {
} else {
result = candidate;
}
}

}
}
public bool defaultHitTestChildren(HitTestResult result, Offset position) {
public bool defaultHitTestChildren(HitTestResult result, Offset position) {
while (child != null) {
while (child != null)
{
return false;
}

return result;
}
}
}

514
Runtime/rendering/editable.cs


using System;
using System.Collections.Generic;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;

return $"Point: {this.point}, Direction: {this.direction}";
}
}
/*
this._doubleTapGesture = new DoubleTapGestureRecognizer(this.rendererBindings.rendererBinding);
this._doubleTapGesture.onDoubleTap = () => { Debug.Log("onDoubleTap"); };*/
static readonly float _kCaretWidth = 1.0f;
bool _hasFocus;
int? _maxLines;
Color _selectionColor;
ViewportOffset _offset;

TextAlign textAlign = TextAlign.left, float textScaleFactor = 1.0f, Color cursorColor = null,
bool? hasFocus = null, int? maxLines = 1, Color selectionColor = null,
TextSelection selection = null, bool obscureText = false, SelectionChangedHandler onSelectionChanged = null,
CaretChangedHandler onCaretChanged = null, bool ignorePointer = false) {
CaretChangedHandler onCaretChanged = null, bool ignorePointer = false,
float cursorWidth = 1.0f,
Radius cursorRadius = null,
bool enableInteractiveSelection = true,
TextSelectionDelegate textSelectionDelegate = null) {
D.assert(textSelectionDelegate != null);
this._textPainter = new TextPainter(text: text, textAlign: textAlign, textDirection: textDirection,
textScaleFactor: textScaleFactor);
this._cursorColor = cursorColor;

this._selection = selection;
this._obscureText = obscureText;
this._offset = offset;
this._cursorWidth = cursorWidth;
this._cursorRadius = cursorRadius;
this._enableInteractiveSelection = enableInteractiveSelection;
this.textSelectionDelegate = textSelectionDelegate;
D.assert(this._maxLines == null || this._maxLines > 0);
D.assert(this._showCursor != null);

}
}
public TextSelectionDelegate textSelectionDelegate;
int _extentOffset = -1;
int _baseOffset = -1;
int _previousCursorLocation;
bool _resetCursor = false;
void _handleKeyEvent(RawKeyEvent keyEvent) {
if (keyEvent is RawKeyUpEvent) {
return;
}
if (this.selection.isCollapsed) {
this._extentOffset = this.selection.extentOffset;
this._baseOffset = this.selection.baseOffset;
}
KeyCode pressedKeyCode = keyEvent.data.unityEvent.keyCode;
int modifiers = (int) keyEvent.data.unityEvent.modifiers;
bool shift = (modifiers & (int)EventModifiers.Shift) > 0;
bool ctrl = (modifiers & (int)EventModifiers.Control) > 0;
bool alt = (modifiers & (int)EventModifiers.Alt) > 0;
bool cmd = (modifiers & (int)EventModifiers.Command) > 0;
bool rightArrow = pressedKeyCode == KeyCode.RightArrow;
bool leftArrow = pressedKeyCode == KeyCode.LeftArrow;
bool upArrow = pressedKeyCode == KeyCode.UpArrow;
bool downArrow = pressedKeyCode == KeyCode.DownArrow;
bool arrow = leftArrow || rightArrow || upArrow || downArrow;
bool aKey = pressedKeyCode == KeyCode.A;
bool xKey = pressedKeyCode == KeyCode.X;
bool vKey = pressedKeyCode == KeyCode.V;
bool cKey = pressedKeyCode == KeyCode.C;
bool del = pressedKeyCode == KeyCode.Delete;
bool isMac = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX;
if (keyEvent is RawKeyCommandEvent) { // editor case
this._handleShortcuts(((RawKeyCommandEvent)keyEvent).command);
return;
}
if ((ctrl || (isMac && cmd)) && (xKey || vKey || cKey || aKey)) { // runtime case
if (xKey) {
this._handleShortcuts(KeyCommand.Cut);
} else if (aKey) {
this._handleShortcuts(KeyCommand.SelectAll);
} else if (vKey) {
this._handleShortcuts(KeyCommand.Paste);
} else if (cKey) {
this._handleShortcuts(KeyCommand.Copy);
}
return;
}
if (arrow) {
int newOffset = this._extentOffset;
var word = (isMac && alt) || ctrl;
if (word) {
newOffset = this._handleControl(rightArrow, leftArrow, word, newOffset);
}
newOffset = this._handleHorizontalArrows(rightArrow, leftArrow, shift, newOffset);
if (downArrow || upArrow)
newOffset = this._handleVerticalArrows(upArrow, downArrow, shift, newOffset);
newOffset = this._handleShift(rightArrow, leftArrow, shift, newOffset);
this._extentOffset = newOffset;
}
if (del) {
this._handleDelete();
}
}
int _handleControl(bool rightArrow, bool leftArrow, bool ctrl, int newOffset) {
// If control is pressed, we will decide which way to look for a word
// based on which arrow is pressed.
if (leftArrow && this._extentOffset > 2) {
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset - 2));
newOffset = textSelection.baseOffset + 1;
} else if (rightArrow && this._extentOffset < this.text.text.Length - 2) {
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset + 1));
newOffset = textSelection.extentOffset - 1;
}
return newOffset;
}
int _handleHorizontalArrows(bool rightArrow, bool leftArrow, bool shift, int newOffset) {
if (rightArrow && this._extentOffset < this.text.text.Length) {
newOffset += 1;
if (shift) {
this._previousCursorLocation += 1;
}
}
if (leftArrow && this._extentOffset > 0) {
newOffset -= 1;
if (shift) {
this._previousCursorLocation -= 1;
}
}
return newOffset;
}
int _handleVerticalArrows(bool upArrow, bool downArrow, bool shift, int newOffset) {
float plh = this._textPainter.preferredLineHeight;
float verticalOffset = upArrow ? -0.5f * plh : 1.5f * plh;
Offset caretOffset = this._textPainter.getOffsetForCaret(new TextPosition(offset: this._extentOffset), this._caretPrototype);
Offset caretOffsetTranslated = caretOffset.translate(0.0f, verticalOffset);
TextPosition position = this._textPainter.getPositionForOffset(caretOffsetTranslated);
if (position.offset == this._extentOffset) {
if (downArrow)
newOffset = this.text.text.Length;
else if (upArrow)
newOffset = 0;
this._resetCursor = shift;
} else if (this._resetCursor && shift) {
newOffset = this._previousCursorLocation;
this._resetCursor = false;
} else {
newOffset = position.offset;
this._previousCursorLocation = newOffset;
}
return newOffset;
}
int _handleShift(bool rightArrow, bool leftArrow, bool shift, int newOffset) {
if (this.onSelectionChanged == null)
return newOffset;
if (shift) {
if (this._baseOffset < newOffset) {
this.onSelectionChanged(
new TextSelection(
baseOffset: this._baseOffset,
extentOffset: newOffset
),
this,
SelectionChangedCause.keyboard
);
} else {
this.onSelectionChanged(
new TextSelection(
baseOffset: newOffset,
extentOffset: this._baseOffset
),
this,
SelectionChangedCause.keyboard
);
}
} else {
if (!this.selection.isCollapsed) {
if (leftArrow)
newOffset = this._baseOffset < this._extentOffset ? this._baseOffset : this._extentOffset;
else if (rightArrow)
newOffset = this._baseOffset > this._extentOffset ? this._baseOffset : this._extentOffset;
}
this.onSelectionChanged(
TextSelection.fromPosition(
new TextPosition(
offset: newOffset
)
),
this,
SelectionChangedCause.keyboard
);
}
return newOffset;
}
void _handleShortcuts(KeyCommand cmd) {
switch (cmd) {
case KeyCommand.Copy:
if (!this.selection.isCollapsed) {
Clipboard.setData(
new ClipboardData(text: this.selection.textInside(this.text.text)));
}
break;
case KeyCommand.Cut:
if (!this.selection.isCollapsed) {
Clipboard.setData(
new ClipboardData(text: this.selection.textInside(this.text.text)));
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: this.selection.textBefore(this.text.text)
+ this.selection.textAfter(this.text.text),
selection: TextSelection.collapsed(offset: this.selection.start)
);
}
break;
case KeyCommand.Paste:
TextEditingValue value = this.textSelectionDelegate.textEditingValue;
Clipboard.getData(Clipboard.kTextPlain).Then(data => {
if (data != null) {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: value.selection.textBefore(value.text)
+ data.text
+ value.selection.textAfter(value.text),
selection: TextSelection.collapsed(
offset: value.selection.start + data.text.Length
)
);
}
});
break;
case KeyCommand.SelectAll:
this._baseOffset = 0;
this._extentOffset = this.textSelectionDelegate.textEditingValue.text.Length;
this.onSelectionChanged(
new TextSelection(
baseOffset: 0,
extentOffset: this.textSelectionDelegate.textEditingValue.text.Length
),
this,
SelectionChangedCause.keyboard
);
break;
default:
D.assert(false);
break;
}
}
void _handleDelete() {
var selection = this.selection;
if (selection.textAfter(this.text.text).isNotEmpty()) {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: selection.textBefore(this.text.text)
+ selection.textAfter(this.text.text).Substring(1),
selection: TextSelection.collapsed(offset: selection.start)
);
} else {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: selection.textBefore(this.text.text),
selection: TextSelection.collapsed(offset: selection.start)
);
}
}
protected void markNeedsTextLayout() {
this._textLayoutLastWidth = null;
this.markNeedsLayout();
}
public TextSpan text {
get { return this._textPainter.text; }
set {

}
}
public ValueNotifier<bool> ShowCursor {
public ValueNotifier<bool> showCursor {
get { return this._showCursor; }
set {
D.assert(value != null);

}
}
bool _hasFocus;
bool _listenerAttached = false;
public bool hasFocus {
get { return this._hasFocus; }
set {

this._hasFocus = value;
if (this._hasFocus) {
D.assert(!this._listenerAttached);
RawKeyboard.instance.addListener(this._handleKeyEvent);
this._listenerAttached = true;
}
else {
D.assert(this._listenerAttached);
RawKeyboard.instance.removeListener(this._handleKeyEvent);
this._listenerAttached = false;
}
this.markNeedsSemanticsUpdate();
}
}

this.markNeedsLayout();
}
}
float _cursorWidth = 1.0f;
public ValueNotifier<bool> showCursor {
get { return this._showCursor; }
set {
D.assert(value != null);
if (this._showCursor == value) {
public float cursorWidth {
get { return this._cursorWidth; }
set {
if (this._cursorWidth == value)
return;
this._cursorWidth = value;
this.markNeedsLayout();
}
}
Radius _cursorRadius;
public Radius cursorRadius {
get { return this._cursorRadius; }
set {
if (this._cursorRadius == value)
}
if (this.attached) {
this._showCursor.removeListener(this.markNeedsPaint);
}
this._showCursor = value;
if (this.attached) {
this._showCursor.addListener(this.markNeedsPaint);
}
this.markNeedsPaint();
this._cursorRadius = value;
this.markNeedsLayout();
}
}
bool _enableInteractiveSelection;
public bool enableInteractiveSelection {
get { return this._enableInteractiveSelection; }
set {
if (this._enableInteractiveSelection == value)
return;
this._enableInteractiveSelection = value;
this.markNeedsTextLayout();
this.markNeedsSemanticsUpdate();
}
}

public override void detach() {
this._offset.removeListener(this.markNeedsLayout);
this._showCursor.removeListener(this.markNeedsPaint);
if (this._listenerAttached) {
RawKeyboard.instance.removeListener(this._handleKeyEvent);
}
base.detach();
}

public Rect getLocalRectForCaret(TextPosition caretPosition) {
this._layoutText(this.constraints.maxWidth);
var caretOffset = this._textPainter.getOffsetForCaret(caretPosition, this._caretPrototype);
return Rect.fromLTWH(0.0f, 0.0f, _kCaretWidth, this.preferredLineHeight)
return Rect.fromLTWH(0.0f, 0.0f, this.cursorWidth, this.preferredLineHeight)
.shift(caretOffset + this._paintOffset);
}

this._longPress.addPointer((PointerDownEvent) evt);
}
}
this._lastTapDownPosition = details.globalPosition - this._paintOffset;
this._lastTapDownPosition = details.globalPosition + - this._paintOffset;
if (!Application.isMobilePlatform) {
this.selectPosition(SelectionChangedCause.tap);
}
}
void _handleTapDown(TapDownDetails details) {
D.assert(!this.ignorePointer);
this.handleTapDown(details);
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (this.onSelectionChanged != null) {
var position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition));
this.onSelectionChanged(TextSelection.fromPosition(position), this, SelectionChangedCause.tap);
}
this.selectPosition(cause: SelectionChangedCause.tap);
}
void _handleTap() {
D.assert(!this.ignorePointer);
this.handleTap();
void _handleDoubleTap(DoubleTapDetails details) {
D.assert(!this.ignorePointer);
this.handleDoubleTap(details);
}
// need set _lastTapDownPosition, otherwise it would be last single tap position
void _handleLongPress() {
D.assert(!this.ignorePointer);
this.handleLongPress();
}
void selectPosition(SelectionChangedCause? cause = null) {
D.assert(cause != null);
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (this.onSelectionChanged != null) {
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition));
this.onSelectionChanged(TextSelection.fromPosition(position), this, cause.Value);
}
}
void selectWord(SelectionChangedCause? cause = null) {
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);

}
}
void selectWordEdge(SelectionChangedCause cause) {
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (this.onSelectionChanged != null) {
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition));
TextRange word = this._textPainter.getWordBoundary(position);
if (position.offset - word.start <= 1) {
this.onSelectionChanged(
TextSelection.collapsed(offset: word.start, affinity: TextAffinity.downstream),
this,
cause
);
} else {
this.onSelectionChanged(
TextSelection.collapsed(offset: word.end, affinity: TextAffinity.upstream),
this,
cause
);
}
}
}
TextSelection _selectWordAtOffset(TextPosition position) {
D.assert(this._textLayoutLastWidth == this.constraints.maxWidth);
var word = this._textPainter.getWordBoundary(position);
if (position.offset >= word.end) {
return TextSelection.fromPosition(position);
}
return new TextSelection(baseOffset: word.start, extentOffset: word.end);
}
void _layoutText(float constraintWidth) {
if (this._textLayoutLastWidth == constraintWidth) {
return;
}
var caretMargin = _kCaretGap + this.cursorWidth;
var avialableWidth = Mathf.Max(0.0f, constraintWidth - caretMargin);
var maxWidth = this._isMultiline ? avialableWidth : float.PositiveInfinity;
this._textPainter.layout(minWidth: avialableWidth, maxWidth: maxWidth);
this._textLayoutLastWidth = constraintWidth;
}
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, _kCaretWidth,
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, this.cursorWidth,
this.preferredLineHeight - 2.0f * _kCaretHeightOffset);
this._selectionRects = null;

var contentSize = new Size(textPainterSize.width + _kCaretGap + _kCaretWidth,
var contentSize = new Size(textPainterSize.width + _kCaretGap + this.cursorWidth,
textPainterSize.height);
var _maxScrollExtent = this._getMaxScrollExtend(contentSize);
this._hasVisualOverflow = _maxScrollExtent > 0.0;

return true;
}
protected void markNeedsTextLayout() {
this._textLayoutLastWidth = null;
this.markNeedsLayout();
}
var caretRec = this._caretPrototype.shift(caretOffset + effectiveOffset);
canvas.drawRect(caretRec, paint);
if (!caretRec.Equals(this._lastCaretRect)) {
this._lastCaretRect = caretRec;
var caretRect = this._caretPrototype.shift(caretOffset + effectiveOffset);
if (this.cursorRadius == null) {
canvas.drawRect(caretRect, paint);
}
else {
RRect caretRRect = RRect.fromRectAndRadius(caretRect, this.cursorRadius);
canvas.drawRRect(caretRRect, paint);
}
if (!caretRect.Equals(this._lastCaretRect)) {
this._lastCaretRect = caretRect;
this.onCaretChanged(caretRec);
this.onCaretChanged(caretRect);
}
}
}

}
}
if (this._hasFocus) {
var caretOffset = this._textPainter.getOffsetForCaret(this._selection.extendPos,
Rect.fromLTWH(0, 0, 1, this.preferredLineHeight));
var caretRec = this._caretPrototype.shift(caretOffset + effectiveOffset);
Input.compositionCursorPos = new Vector2(caretRec.left, caretRec.bottom);
}
void _handleSetSelection(TextSelection selection) {
this.onSelectionChanged(selection, this, SelectionChangedCause.keyboard);
}
void _handleTapDown(TapDownDetails details) {
D.assert(!this.ignorePointer);
this.handleTapDown(details);
}
void _handleTap() {
D.assert(!this.ignorePointer);
this.handleTap();
}
void _handleDoubleTap(DoubleTapDetails details) {
D.assert(!this.ignorePointer);
this.handleDoubleTap(details);
}
void _handleLongPress() {
D.assert(!this.ignorePointer);
this.handleLongPress();
}
void markNeedsSemanticsUpdate() {
// todo
}

return Mathf.Max(this.preferredLineHeight, this._textPainter.height);
}
void _layoutText(float constraintWidth) {
if (this._textLayoutLastWidth == constraintWidth) {
return;
}
var caretMargin = _kCaretGap + _kCaretWidth;
var avialableWidth = Mathf.Max(0.0f, constraintWidth - caretMargin);
var maxWidth = this._isMultiline ? avialableWidth : float.PositiveInfinity;
this._textPainter.layout(minWidth: avialableWidth, maxWidth: maxWidth);
this._textLayoutLastWidth = constraintWidth;
}
TextSelection _selectWordAtOffset(TextPosition position) {
D.assert(this._textLayoutLastWidth == this.constraints.maxWidth);
var word = this._textPainter.getWordBoundary(position);
if (position.offset >= word.end) {
return TextSelection.fromPosition(position);
}
return new TextSelection(baseOffset: word.start, extentOffset: word.end);
}
bool _isMultiline {
get { return this._maxLines != 1; }
}

return 0.0f;
}
public override Rect describeApproximatePaintClip(RenderObject child) {
return this._hasVisualOverflow ? Offset.zero & this.size : null;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Color>("cursorColor", this.cursorColor));

221
Runtime/rendering/layer.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
namespace Unity.UIWidgets.rendering {
public abstract class Layer : AbstractNodeMixinDiagnosticableTree {

public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Rect>("paint bounds", this.canvasBounds));
}
}
public class TextureLayer : Layer {
public TextureLayer(
Rect rect,
Texture texture,
bool freeze = false
) {
D.assert(rect != null);
D.assert(texture != null);
this.rect = rect;
this.texture = texture;
this.freeze = freeze;
}
public readonly Rect rect;
public readonly Texture texture;
public readonly bool freeze;
internal override flow.Layer addToScene(SceneBuilder builder, Offset layerOffset = null) {
layerOffset = layerOffset ?? Offset.zero;
Rect shiftedRect = this.rect.shift(layerOffset);
builder.addTexture(
this.texture,
offset: shiftedRect.topLeft,
width: shiftedRect.width,
height: shiftedRect.height,
freeze: this.freeze
);
return null;
}
}

properties.add(new DiagnosticsProperty<Offset>("offset", this.offset));
}
}
public class BackdropFilterLayer : ContainerLayer {
public BackdropFilterLayer(ImageFilter filter = null) {
D.assert(filter != null);
this._filter = filter;
}
ImageFilter _filter;
public ImageFilter filter {
get { return this._filter; }
set {
if (value != this._filter) {
this._filter = value;
this.markNeedsAddToScene();
}
}
}
internal override flow.Layer addToScene(SceneBuilder builder, Offset layerOffset = null) {
builder.pushBackdropFilter(this.filter);
this.addChildrenToScene(builder, layerOffset);
builder.pop();
return null;
}
}
public class LayerLink {
public LeaderLayer leader {

properties.add(new DiagnosticsProperty<LayerLink>("link", this.link));
properties.add(new TransformProperty("transform", this.getLastTransform(),
defaultValue: Diagnostics.kNullDefaultValue));
}
}
public class PerformanceOverlayLayer : Layer {
public PerformanceOverlayLayer(
Rect overlayRect = null,
int? optionsMask = null
) {
D.assert(overlayRect != null);
D.assert(optionsMask != null);
this._overlayRect = overlayRect;
this.optionsMask = optionsMask ?? 0;
}
public Rect overlayRect {
get { return this._overlayRect; }
set {
if (value != this._overlayRect) {
this._overlayRect = value;
this.markNeedsAddToScene();
}
}
}
Rect _overlayRect;
public readonly int optionsMask;
internal override flow.Layer addToScene(SceneBuilder builder, Offset layerOffset = null) {
layerOffset = layerOffset ?? Offset.zero;
builder.addPerformanceOverlay(this.optionsMask, this.overlayRect.shift(layerOffset));
return null;
}
}
public class AnnotatedRegionLayer<T> : ContainerLayer
where T : class {
public AnnotatedRegionLayer(
T value = null,
Size size = null) {
D.assert(value != null);
this.value = value;
this.size = size;
}
public readonly T value;
public readonly Size size;
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<T>("value", this.value));
properties.add(new DiagnosticsProperty<Size>("size", this.size, defaultValue: null));
}
}
public class PhysicalModelLayer : ContainerLayer {
public PhysicalModelLayer(
Path clipPath = null,
Clip clipBehavior = Clip.none,
float? elevation = null,
Color color = null,
Color shadowColor = null) {
D.assert(clipPath != null);
D.assert(elevation != null);
D.assert(color != null);
D.assert(shadowColor != null);
this._clipPath = clipPath;
this._clipBehavior = clipBehavior;
this._elevation = elevation.Value;
this._color = color;
this.shadowColor = shadowColor;
}
public Path clipPath {
get { return this._clipPath; }
set {
if (value != this._clipPath) {
this._clipPath = value;
this.markNeedsAddToScene();
}
}
}
Path _clipPath;
public Clip clipBehavior {
get { return this._clipBehavior; }
set {
if (value != this._clipBehavior) {
this._clipBehavior = value;
this.markNeedsAddToScene();
}
}
}
Clip _clipBehavior;
public float elevation {
get { return this._elevation; }
set {
if (value != this._elevation) {
this._elevation = value;
this.markNeedsAddToScene();
}
}
}
float _elevation;
public Color color {
get { return this._color; }
set {
if (value != this._color) {
this._color = value;
this.markNeedsAddToScene();
}
}
}
Color _color;
public Color shadowColor {
get { return this._shadowColor; }
set {
if (value != this._shadowColor) {
this._shadowColor = value;
this.markNeedsAddToScene();
}
}
}
Color _shadowColor;
internal override flow.Layer addToScene(SceneBuilder builder, Offset layerOffset = null) {
layerOffset = layerOffset ?? Offset.zero;
builder.pushPhysicalShape(
path: this.clipPath.shift(layerOffset),
elevation: this.elevation,
color: this.color,
shadowColor: this.shadowColor,
clipBehavior: this.clipBehavior);
this.addChildrenToScene(builder, layerOffset);
builder.pop();
return null;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new FloatProperty("elevation", this.elevation));
properties.add(new DiagnosticsProperty<Color>("color", this.color));
}
}
}

24
Runtime/rendering/object.cs


}
}
public void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath,
PaintingContextCallback painter, Clip clipBehavior = Clip.antiAlias) {
Rect offsetBounds = bounds.shift(offset);
Path offsetClipPath = clipPath.shift(offset);
if (needsCompositing) {
this.pushLayer(new ClipPathLayer(clipPath: offsetClipPath, clipBehavior: clipBehavior), painter, offset,
childPaintBounds: offsetBounds);
}
else {
this.clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset));
}
}
var effectiveTransform = Matrix3.makeTrans(offset.dx, offset.dy);
effectiveTransform.preConcat(transform);
effectiveTransform.preTranslate(-offset.dx, -offset.dy);
Matrix3 effectiveTransform;
if (offset == null || offset == Offset.zero) {
effectiveTransform = transform;
} else {
effectiveTransform = Matrix3.makeTrans(offset.dx, offset.dy);
effectiveTransform.preConcat(transform);
effectiveTransform.preTranslate(-offset.dx, -offset.dy);
}
if (needsCompositing) {
var inverse = Matrix3.I();

90
Runtime/rendering/object.mixin.gen.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using UnityEngine;
public abstract class RenderObjectWithChildMixinRenderObject<ChildType> : RenderObject,
RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public abstract class RenderObjectWithChildMixinRenderObject<ChildType> : RenderObject, RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public bool debugValidateChild(RenderObject child) {
D.assert(() => {
if (!(child is ChildType)) {

public override List<DiagnosticsNode> debugDescribeChildren() {
return this.child != null
? new List<DiagnosticsNode> {this.child.toDiagnosticsNode(name: "child")}
? new List<DiagnosticsNode>{this.child.toDiagnosticsNode(name: "child")}
public abstract class RenderObjectWithChildMixinRenderBox<ChildType> : RenderBox,
RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public abstract class RenderObjectWithChildMixinRenderBox<ChildType> : RenderBox, RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public bool debugValidateChild(RenderObject child) {
D.assert(() => {
if (!(child is ChildType)) {

public override List<DiagnosticsNode> debugDescribeChildren() {
return this.child != null
? new List<DiagnosticsNode> {this.child.toDiagnosticsNode(name: "child")}
? new List<DiagnosticsNode>{this.child.toDiagnosticsNode(name: "child")}
public abstract class RenderObjectWithChildMixinRenderSliver<ChildType> : RenderSliver,
RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public abstract class RenderObjectWithChildMixinRenderSliver<ChildType> : RenderSliver, RenderObjectWithChildMixin<ChildType>, RenderObjectWithChildMixin where ChildType : RenderObject {
public bool debugValidateChild(RenderObject child) {
D.assert(() => {
if (!(child is ChildType)) {

public override List<DiagnosticsNode> debugDescribeChildren() {
return this.child != null
? new List<DiagnosticsNode> {this.child.toDiagnosticsNode(name: "child")}
? new List<DiagnosticsNode>{this.child.toDiagnosticsNode(name: "child")}
public abstract class ContainerParentDataMixinParentData<ChildType> : ParentData,
ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public abstract class ContainerParentDataMixinParentData<ChildType> : ParentData, ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public ChildType previousSibling { get; set; }
public ChildType nextSibling { get; set; }

}
public abstract class ContainerParentDataMixinBoxParentData<ChildType> : BoxParentData,
ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public abstract class ContainerParentDataMixinBoxParentData<ChildType> : BoxParentData, ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public ChildType previousSibling { get; set; }
public ChildType nextSibling { get; set; }

}
public abstract class ContainerParentDataMixinSliverPhysicalParentData<ChildType> : SliverPhysicalParentData,
ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public abstract class ContainerParentDataMixinSliverPhysicalParentData<ChildType> : SliverPhysicalParentData, ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public ChildType previousSibling { get; set; }
public ChildType nextSibling { get; set; }

}
public abstract class ContainerParentDataMixinSliverLogicalParentData<ChildType> : SliverLogicalParentData,
ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public abstract class ContainerParentDataMixinSliverLogicalParentData<ChildType> : SliverLogicalParentData, ContainerParentDataMixin<ChildType> where ChildType : RenderObject {
public ChildType previousSibling { get; set; }
public ChildType nextSibling { get; set; }

}
public abstract class ContainerRenderObjectMixinRenderBox<ChildType, ParentDataType> : RenderBox,
ContainerRenderObjectMixin
public abstract class ContainerRenderObjectMixinRenderBox<ChildType, ParentDataType> : RenderBox, ContainerRenderObjectMixin
bool _debugUltimatePreviousSiblingOf(ChildType child, ChildType equals = null) {
ParentDataType childParentData = (ParentDataType) child.parentData;
while (childParentData.previousSibling != null) {

this._firstChild = child;
this._lastChild = this._lastChild ?? child;
}
else {
} else {
D.assert(this._firstChild != null);
D.assert(this._lastChild != null);
D.assert(this._debugUltimatePreviousSiblingOf(after, equals: this._firstChild));

childParentData.previousSibling = after;
afterParentData.nextSibling = child;
this._lastChild = child;
}
else {
} else {
childParentData.nextSibling = afterParentData.nextSibling;
childParentData.previousSibling = after;
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;

if (childParentData.previousSibling == null) {
D.assert(this._firstChild == child);
this._firstChild = childParentData.nextSibling;
}
else {
} else {
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;
childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
}

this._lastChild = childParentData.previousSibling;
}
else {
} else {
var childNextSiblingParentData = (ParentDataType) childParentData.nextSibling.parentData;
childNextSiblingParentData.previousSibling = childParentData.previousSibling;
}

}
public abstract class ContainerRenderObjectMixinRenderSliver<ChildType, ParentDataType> : RenderSliver,
ContainerRenderObjectMixin
public abstract class ContainerRenderObjectMixinRenderSliver<ChildType, ParentDataType> : RenderSliver, ContainerRenderObjectMixin
bool _debugUltimatePreviousSiblingOf(ChildType child, ChildType equals = null) {
ParentDataType childParentData = (ParentDataType) child.parentData;
while (childParentData.previousSibling != null) {

this._firstChild = child;
this._lastChild = this._lastChild ?? child;
}
else {
} else {
D.assert(this._firstChild != null);
D.assert(this._lastChild != null);
D.assert(this._debugUltimatePreviousSiblingOf(after, equals: this._firstChild));

childParentData.previousSibling = after;
afterParentData.nextSibling = child;
this._lastChild = child;
}
else {
} else {
childParentData.nextSibling = afterParentData.nextSibling;
childParentData.previousSibling = after;
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;

if (childParentData.previousSibling == null) {
D.assert(this._firstChild == child);
this._firstChild = childParentData.nextSibling;
}
else {
} else {
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;
childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
}

this._lastChild = childParentData.previousSibling;
}
else {
} else {
var childNextSiblingParentData = (ParentDataType) childParentData.nextSibling.parentData;
childNextSiblingParentData.previousSibling = childParentData.previousSibling;
}

}
public abstract class
ContainerRenderObjectMixinRenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack<ChildType,
ParentDataType> : RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack,
ContainerRenderObjectMixin
public abstract class ContainerRenderObjectMixinRenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack<ChildType, ParentDataType> : RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack, ContainerRenderObjectMixin
bool _debugUltimatePreviousSiblingOf(ChildType child, ChildType equals = null) {
ParentDataType childParentData = (ParentDataType) child.parentData;
while (childParentData.previousSibling != null) {

get { return this._childCount; }
}
public bool debugValidateChild(RenderObject child) {
public new bool debugValidateChild(RenderObject child) {
D.assert(() => {
if (!(child is ChildType)) {
throw new UIWidgetsError(

this._firstChild = child;
this._lastChild = this._lastChild ?? child;
}
else {
} else {
D.assert(this._firstChild != null);
D.assert(this._lastChild != null);
D.assert(this._debugUltimatePreviousSiblingOf(after, equals: this._firstChild));

childParentData.previousSibling = after;
afterParentData.nextSibling = child;
this._lastChild = child;
}
else {
} else {
childParentData.nextSibling = afterParentData.nextSibling;
childParentData.previousSibling = after;
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;

if (childParentData.previousSibling == null) {
D.assert(this._firstChild == child);
this._firstChild = childParentData.nextSibling;
}
else {
} else {
var childPreviousSiblingParentData = (ParentDataType) childParentData.previousSibling.parentData;
childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
}

this._lastChild = childParentData.previousSibling;
}
else {
} else {
var childNextSiblingParentData = (ParentDataType) childParentData.nextSibling.parentData;
childNextSiblingParentData.previousSibling = childParentData.previousSibling;
}

return this.childAfter((ChildType) child);
}
}
}

19
Runtime/rendering/paragraph.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Rect = Unity.UIWidgets.ui.Rect;
namespace Unity.UIWidgets.rendering {
public enum TextOverflow {

}
}
protected Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) {
D.assert(this._textPainter != null);
return this._textPainter.getOffsetForCaret(position, caretPrototype);
}
public bool softWrap {
get { return this._softWrap; }
set {

protected override bool hitTestSelf(Offset position) {
return true;
}
public override void handleEvent(PointerEvent evt, HitTestEntry entry) {
D.assert(this.debugHandleEvent(evt, entry));
if (!(evt is PointerDownEvent)) {
return;
}
this._layoutTextWithConstraints(this.constraints);
Offset offset = ((BoxHitTestEntry)entry).localPosition;
TextPosition position = this._textPainter.getPositionForOffset(offset);
TextSpan span = this._textPainter.text.getSpanForPosition(position);
span?.recognizer?.addPointer((PointerDownEvent)evt);
}
protected override void performLayout() {

581
Runtime/rendering/proxy_box.cs


using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Gradient = Unity.UIWidgets.ui.Gradient;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.rendering {
public class RenderProxyBox : RenderProxyBoxMixinRenderObjectWithChildMixinRenderBox<RenderBox> {

};
context.canvas.drawRect(offset & this.size, paint);
}
return true;
});
}

}
}
public class RenderIntrinsicWidth : RenderProxyBox {
public RenderIntrinsicWidth(
float? stepWidth = null,
float? stepHeight = null,
RenderBox child = null
) : base(child) {
this._stepWidth = stepWidth;
this._stepHeight = stepHeight;
}
float? _stepWidth;
public float? stepWidth {
get { return this._stepWidth; }
set {
if (value == this._stepWidth) {
return;
}
this._stepWidth = value;
this.markNeedsLayout();
}
}
float? _stepHeight;
public float? stepHeight {
get { return this._stepHeight; }
set {
if (value == this._stepHeight) {
return;
}
this._stepHeight = value;
this.markNeedsLayout();
}
}
static float _applyStep(float input, float? step) {
D.assert(input.isFinite());
if (step == null) {
return input;
}
return (input / step.Value).ceil() * step.Value;
}
protected override float computeMinIntrinsicWidth(float height) {
return this.computeMaxIntrinsicWidth(height);
}
protected override float computeMaxIntrinsicWidth(float height) {
if (this.child == null) {
return 0.0f;
}
float width = this.child.getMaxIntrinsicWidth(height);
return _applyStep(width, this._stepWidth);
}
protected override float computeMinIntrinsicHeight(float width) {
if (this.child == null) {
return 0.0f;
}
if (!width.isFinite()) {
width = this.computeMaxIntrinsicWidth(float.PositiveInfinity);
}
D.assert(width.isFinite());
float height = this.child.getMinIntrinsicHeight(width);
return _applyStep(height, this._stepHeight);
}
protected override float computeMaxIntrinsicHeight(float width) {
if (this.child == null) {
return 0.0f;
}
if (!width.isFinite()) {
width = this.computeMaxIntrinsicWidth(float.PositiveInfinity);
}
D.assert(width.isFinite());
float height = this.child.getMaxIntrinsicHeight(width);
return _applyStep(height, this._stepHeight);
}
protected override void performLayout() {
if (this.child != null) {
BoxConstraints childConstraints = this.constraints;
if (!childConstraints.hasTightWidth) {
float width = this.child.getMaxIntrinsicWidth(childConstraints.maxHeight);
D.assert(width.isFinite());
childConstraints = childConstraints.tighten(width: _applyStep(width, this._stepWidth));
}
if (this._stepHeight != null) {
float height = this.child.getMaxIntrinsicHeight(childConstraints.maxWidth);
D.assert(height.isFinite());
childConstraints = childConstraints.tighten(height: _applyStep(height, this._stepHeight));
}
this.child.layout(childConstraints, parentUsesSize: true);
this.size = this.child.size;
}
else {
this.performResize();
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new FloatProperty("stepWidth", this.stepWidth));
properties.add(new FloatProperty("stepHeight", this.stepHeight));
}
}
public class RenderIntrinsicHeight : RenderProxyBox {
public RenderIntrinsicHeight(
RenderBox child = null
) : base(child) {
}
protected override float computeMinIntrinsicWidth(float height) {
if (this.child == null) {
return 0.0f;
}
if (!height.isFinite()) {
height = this.child.getMaxIntrinsicHeight(float.PositiveInfinity);
}
D.assert(height.isFinite());
return this.child.getMinIntrinsicWidth(height);
}
protected override float computeMaxIntrinsicWidth(float height) {
if (this.child == null) {
return 0.0f;
}
if (!height.isFinite()) {
height = this.child.getMaxIntrinsicHeight(float.PositiveInfinity);
}
D.assert(height.isFinite());
return this.child.getMaxIntrinsicWidth(height);
}
protected override float computeMinIntrinsicHeight(float width) {
return this.computeMaxIntrinsicHeight(width);
}
protected override void performLayout() {
if (this.child != null) {
BoxConstraints childConstraints = this.constraints;
if (!childConstraints.hasTightHeight) {
float height = this.child.getMaxIntrinsicHeight(childConstraints.maxWidth);
D.assert(height.isFinite());
childConstraints = childConstraints.tighten(height: height);
}
this.child.layout(childConstraints, parentUsesSize: true);
this.size = this.child.size;
}
else {
this.performResize();
}
}
}
public class RenderOpacity : RenderProxyBox {
public RenderOpacity(float opacity = 1.0f, RenderBox child = null) : base(child) {
D.assert(opacity >= 0.0 && opacity <= 1.0);

}
}
public class RenderBackdropFilter : RenderProxyBox {
public RenderBackdropFilter(
RenderBox child = null,
ImageFilter filter = null
) : base(child) {
D.assert(filter != null);
this._filter = filter;
}
ImageFilter _filter;
public ImageFilter filter {
get { return this._filter; }
set {
D.assert(value != null);
if (this._filter == value) {
return;
}
this.markNeedsPaint();
}
}
protected override bool alwaysNeedsCompositing {
get { return this.child != null; }
}
public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {
D.assert(this.needsCompositing);
context.pushLayer(new BackdropFilterLayer(this.filter), base.paint, offset);
}
}
}
public abstract class CustomClipper<T> {
public CustomClipper(Listenable reclip = null) {

public abstract T getClip(Size size);
public Rect getApproximateClipRect(Size size) {
public virtual Rect getApproximateClipRect(Size size) {
return Offset.zero & size;
}

protected override void debugPaintSize(PaintingContext context, Offset offset) {
D.assert(() => {
// if (this._debugPaint == null) {
// this._debugPaint = new Paint();
// this._debugPaint.shader = Gradient.linear(
// new Offset(0.0, 0.0),
// new Offset(10.0, 10.0),
// new Color(0x00000000),
// new Color(0xFFFF00FF),
// TileMode.repeated);
// this._debugPaint.strokeWidth = 2.0;
// this._debugPaint.style = PaintingStyle.stroke;
// }
// if (this._debugText == null) {
// this._debugText = new TextPainter(
// text: new TextSpan(
// text: "x",
// style: new TextStyle(
// color: new Color(0xFFFF00FF),
// fontSize: 14.0)
// ));
// this._debugText.layout();
// }
if (this._debugPaint == null) {
this._debugPaint = new Paint();
this._debugPaint.shader = Gradient.linear(
new Offset(0.0f, 0.0f),
new Offset(10.0f, 10.0f),
new List<Color> {
new Color(0x00000000),
new Color(0xFFFF00FF),
}, null, TileMode.repeated);
this._debugPaint.strokeWidth = 2.0f;
this._debugPaint.style = PaintingStyle.stroke;
}
if (this._debugText == null) {
this._debugText = new TextPainter(
text: new TextSpan(
text: "x",
style: new TextStyle(
color: new Color(0xFFFF00FF),
fontSize: 14.0f)
));
this._debugText.layout();
}
public class RenderClipRect : _RenderCustomClip<Rect> {
public RenderClipRect(

}
public override bool hitTest(HitTestResult result, Offset position = null) {
D.assert(position != null);
if (this._clipper != null) {
this._updateClip();
D.assert(this._clip != null);

public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {
this._updateClip();
//todo:xingwei.zhu pushClipPath()
// context.pushClipPath(this.needsCompositing, offset, Offset.zero & this.size,
// this._clip, base.paint, clipBehavior: this.clipBehavior);
context.pushClipPath(this.needsCompositing, offset, Offset.zero & this.size,
this._clip, base.paint, clipBehavior: this.clipBehavior);
base.paint(context, offset);
}
}

Color _color;
static Paint _transparentPaint {
protected static Paint _transparentPaint {
get { return new Paint {color = new Color(0x00000000)}; }
}

return base.hitTest(result, position: position);
}
//todo:xingwei.zhu: implementation shadow + compositeLayer (issue: no color when composite)
public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {
this._updateClip();

offsetRRectAsPath.addRRect(offsetRRect);
Canvas canvas = context.canvas;
if (this.elevation != 0.0) {
//draw Shadow
/*canvas.drawRect(
offsetBounds.inflate(20.0),
_RenderPhysicalModelBase<RRect>._transparentPaint
);
canvas.drawShadow(
offsetRRectAsPath,
this.shadowColor,
this.elevation,
this.color.alpha != 0xFF
);*/
if (this.needsCompositing) {
PhysicalModelLayer physicalModel = new PhysicalModelLayer(
clipPath: offsetRRectAsPath,
clipBehavior: this.clipBehavior,
elevation: this.elevation,
color: this.color,
shadowColor: this.shadowColor);
context.pushLayer(physicalModel, base.paint, offset, childPaintBounds: offsetBounds);
else {
Canvas canvas = context.canvas;
if (this.elevation != 0.0) {
canvas.drawRect(
offsetBounds.inflate(20.0f),
_transparentPaint
);
canvas.drawShadow(
offsetRRectAsPath,
this.shadowColor,
this.elevation,
this.color.alpha != 0xFF
);
}
if (this.needsCompositing) {
ContainerLayer container = new ContainerLayer();
context.pushLayer(container, base.paint, offset, childPaintBounds: offsetBounds);
return;
Paint paint = new Paint {color = this.color};
canvas.drawRRect(offsetRRect, paint);
context.clipRRectAndPaint(offsetRRect, this.clipBehavior, offsetBounds,
() => base.paint(context, offset));
D.assert(context.canvas == canvas, "canvas changed even though needsCompositing was false");
Paint paint = new Paint {color = this.color};
canvas.drawRRect(offsetRRect, paint);
context.clipRRectAndPaint(offsetRRect, this.clipBehavior, offsetBounds,
() => base.paint(context, offset));
D.assert(context.canvas == canvas, "canvas changed even though needsCompositing was false");
}
}

return base.hitTest(result, position: position);
}
//todo:xingwei.zhu: implementation shadow + compositeLayer (issue: no color when composite)
public override void paint(PaintingContext context, Offset offset) {
if (this.child != null) {
this._updateClip();

Canvas canvas = context.canvas;
// if (this.elevation != 0.0 && paintShadows) {
// canvas.drawRect(
// offsetBounds.inflate(20.0),
// _RenderPhysicalModelBase<Path>._transparentPaint
// );
// canvas.drawShadow(
// offsetPath,
// this.shadowColor,
// this.elevation,
// this.color.alpha != 0xFF,
// );
// }
ContainerLayer container = new ContainerLayer();
context.pushLayer(container, base.paint, offset, childPaintBounds: offsetBounds);
return;
PhysicalModelLayer physicalModel = new PhysicalModelLayer(
clipPath: offsetPath,
clipBehavior: this.clipBehavior,
elevation: this.elevation,
color: this.color,
shadowColor: this.shadowColor);
context.pushLayer(physicalModel, base.paint, offset, childPaintBounds: offsetBounds);
Paint paint = new Paint {color = this.color, style = PaintingStyle.fill};
canvas.drawPath(offsetPath, paint);
context.clipPathAndPaint(offsetPath, this.clipBehavior,
offsetBounds, () => base.paint(context, offset));
D.assert(context.canvas == canvas, "canvas changed even though needsCompositing was false");
else {
Canvas canvas = context.canvas;
if (this.elevation != 0.0) {
canvas.drawRect(
offsetBounds.inflate(20.0f),
_transparentPaint
);
canvas.drawShadow(
offsetPath,
this.shadowColor,
this.elevation,
this.color.alpha != 0xFF
);
}
Paint paint = new Paint {color = this.color, style = PaintingStyle.fill};
canvas.drawPath(offsetPath, paint);
context.clipPathAndPaint(offsetPath, this.clipBehavior,
offsetBounds, () => base.paint(context, offset));
D.assert(context.canvas == canvas, "canvas changed even though needsCompositing was false");
}
}
}

properties.add(new DiagnosticsProperty<Offset>("origin", this.origin));
properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment));
properties.add(new DiagnosticsProperty<bool>("transformHitTests", this.transformHitTests));
}
}
public class RenderFittedBox : RenderProxyBox {
public RenderFittedBox(
BoxFit fit = BoxFit.contain,
Alignment alignment = null,
RenderBox child = null
) : base(child) {
this._fit = fit;
this._alignment = alignment ?? Alignment.center;
}
Alignment _resolvedAlignment;
void _resolve() {
if (this._resolvedAlignment != null) {
return;
}
this._resolvedAlignment = this.alignment;
}
void _markNeedResolution() {
this._resolvedAlignment = null;
this.markNeedsPaint();
}
public BoxFit fit {
get { return this._fit; }
set {
if (this._fit == value) {
return;
}
this._fit = value;
this._clearPaintData();
this.markNeedsPaint();
}
}
BoxFit _fit;
public Alignment alignment {
get { return this._alignment; }
set {
D.assert(value != null);
if (this._alignment == value) {
return;
}
this._alignment = value;
this._clearPaintData();
this._markNeedResolution();
}
}
Alignment _alignment;
protected override void performLayout() {
if (this.child != null) {
this.child.layout(new BoxConstraints(), parentUsesSize: true);
this.size = this.constraints.constrainSizeAndAttemptToPreserveAspectRatio(this.child.size);
this._clearPaintData();
}
else {
this.size = this.constraints.smallest;
}
}
bool? _hasVisualOverflow;
Matrix3 _transform;
void _clearPaintData() {
this._hasVisualOverflow = null;
this._transform = null;
}
void _updatePaintData() {
if (this._transform != null) {
return;
}
if (this.child == null) {
this._hasVisualOverflow = false;
this._transform = Matrix3.I();
}
else {
this._resolve();
Size childSize = this.child.size;
FittedSizes sizes = FittedSizes.applyBoxFit(this._fit, childSize, this.size);
float scaleX = sizes.destination.width / sizes.source.width;
float scaleY = sizes.destination.height / sizes.source.height;
Rect sourceRect = this._resolvedAlignment.inscribe(sizes.source, Offset.zero & childSize);
Rect destinationRect = this._resolvedAlignment.inscribe(sizes.destination, Offset.zero & this.size);
this._hasVisualOverflow = sourceRect.width < childSize.width || sourceRect.height < childSize.height;
this._transform = Matrix3.makeTrans(destinationRect.left, destinationRect.top);
this._transform.postScale(scaleX, scaleY);
this._transform.postTranslate(-sourceRect.left, -sourceRect.top);
}
}
void _paintChildWithTransform(PaintingContext context, Offset offset) {
Offset childOffset = this._transform.getAsTranslation();
if (childOffset == null) {
context.pushTransform(this.needsCompositing, offset, this._transform, base.paint);
}
else {
base.paint(context, offset + childOffset);
}
}
public override void paint(PaintingContext context, Offset offset) {
if (this.size.isEmpty) {
return;
}
this._updatePaintData();
if (this.child != null) {
if (this._hasVisualOverflow == true) {
context.pushClipRect(this.needsCompositing, offset, Offset.zero & this.size,
this._paintChildWithTransform);
}
else {
this._paintChildWithTransform(context, offset);
}
}
}
protected override bool hitTestChildren(HitTestResult result, Offset position = null) {
if (this.size.isEmpty) {
return false;
}
this._updatePaintData();
Matrix3 inverse = Matrix3.I();
if (!this._transform.invert(inverse)) {
return false;
}
position = inverse.mapPoint(position);
return base.hitTestChildren(result, position: position);
}
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
if (this.size.isEmpty) {
transform.setAll(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
else {
this._updatePaintData();
transform.postConcat(this._transform);
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new EnumProperty<BoxFit>("fit", this.fit));
properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment));
}
}

properties.add(new DiagnosticsProperty<bool>("showWhenUnlinked", this.showWhenUnlinked));
properties.add(new DiagnosticsProperty<Offset>("offset", this.offset));
properties.add(new TransformProperty("current transform matrix", this.getCurrentTransform()));
}
}
public class RenderAnnotatedRegion<T> : RenderProxyBox
where T : class {
public RenderAnnotatedRegion(
T value = null,
bool? sized = null,
RenderBox child = null
) : base(child: child) {
D.assert(value != null);
D.assert(sized != null);
this._value = value;
this._sized = sized.Value;
}
public T value {
get { return this._value; }
set {
if (this._value == value) {
return;
}
this._value = value;
this.markNeedsPaint();
}
}
T _value;
public bool sized {
get { return this._sized; }
set {
if (this._sized == value) {
return;
}
this._sized = value;
this.markNeedsPaint();
}
}
bool _sized;
protected override bool alwaysNeedsCompositing {
get { return true; }
}
public override void paint(PaintingContext context, Offset offset) {
AnnotatedRegionLayer<T> layer =
new AnnotatedRegionLayer<T>(value: this.value, size: this.sized ? this.size : null);
context.pushLayer(layer, base.paint, offset);
}
}
}

20
Runtime/rendering/proxy_box.mixin.gen.cs


using Unity.UIWidgets.gestures;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.gestures;
using UnityEngine;
public abstract class
RenderProxyBoxMixinRenderObjectWithChildMixinRenderBox<T> : RenderObjectWithChildMixinRenderBox<T>
where T : RenderBox {
public abstract class RenderProxyBoxMixinRenderObjectWithChildMixinRenderBox<T> : RenderObjectWithChildMixinRenderBox<T> where T : RenderBox {
public override void setupParentData(RenderObject child) {
if (!(child.parentData is ParentData)) {
child.parentData = new ParentData();

if (this.child != null) {
this.child.layout(this.constraints, parentUsesSize: true);
this.size = this.child.size;
}
else {
} else {
this.performResize();
}
}

}
public abstract class RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack :
public abstract class RenderProxyBoxMixinRenderObjectWithChildMixinRenderBoxRenderStack:
}
}

87
Runtime/rendering/stack.cs


container.height - this.bottom);
}
public static RelativeRect lerp(RelativeRect a, RelativeRect b, float t) {
if (a == null && b == null) {
return null;
}
if (a == null) {
return fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
}
if (b == null) {
float k = 1.0f - t;
return fromLTRB(b.left * k, b.top * k, b.right * k, b.bottom * k);
}
return fromLTRB(
MathUtils.lerpFloat(a.left, b.left, t),
MathUtils.lerpFloat(a.top, b.top, t),
MathUtils.lerpFloat(a.right, b.right, t),
MathUtils.lerpFloat(a.bottom, b.bottom, t)
);
}
public bool Equals(RelativeRect other) {
if (ReferenceEquals(null, other)) {
return false;

return this.defaultHitTestChildren(result, position: position);
}
public void paintStack(PaintingContext context, Offset offset) {
public virtual void paintStack(PaintingContext context, Offset offset) {
this.defaultPaint(context, offset);
}

properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment));
properties.add(new EnumProperty<StackFit>("fit", this.fit));
properties.add(new EnumProperty<Overflow>("overflow", this.overflow));
}
}
class RenderIndexedStack : RenderStack {
public RenderIndexedStack(
List<RenderBox> children = null,
Alignment alignment = null,
int? index = 0
) : base(fit: null, overflow: null, children: children, alignment: alignment ?? Alignment.topLeft) {
this._index = index;
}
public int? index {
get { return this._index; }
set {
if (this._index != value) {
this._index = value;
this.markNeedsLayout();
}
}
}
int? _index;
RenderBox _childAtIndex() {
D.assert(this.index != null);
RenderBox child = this.firstChild;
int i = 0;
while (child != null && i < this.index) {
StackParentData childParentData = (StackParentData) child.parentData;
child = childParentData.nextSibling;
i += 1;
}
D.assert(i == this.index);
D.assert(child != null);
return child;
}
protected override bool hitTestChildren(HitTestResult result, Offset position) {
if (this.firstChild == null || this.index == null) {
return false;
}
D.assert(position != null);
RenderBox child = this._childAtIndex();
StackParentData childParentData = (StackParentData) child.parentData;
return child.hitTest(result, position: position - childParentData.offset);
}
public override void paintStack(PaintingContext context, Offset offset) {
if (this.firstChild == null || this.index == null) {
return;
}
RenderBox child = this._childAtIndex();
StackParentData childParentData = (StackParentData) child.parentData;
context.paintChild(child, childParentData.offset + offset);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new IntProperty("index", this.index));
}
}
}

8
Runtime/rendering/viewport.cs


D.assert(targetOffset != null);
if (duration == TimeSpan.Zero) {
offset.jumpTo(targetOffset.offset);
}
else {
offset.animateTo(targetOffset.offset, duration: duration.Value, curve: curve);
}
offset.moveTo(targetOffset.offset, duration: duration.Value, curve: curve);
return targetOffset.rect;
}
}

9
Runtime/rendering/viewport_offset.cs


public abstract IPromise animateTo(float to, TimeSpan duration, Curve curve);
public virtual IPromise moveTo(float to, TimeSpan? duration, Curve curve = null, bool clamp = true) {
if (duration == null || duration.Value == TimeSpan.Zero) {
this.jumpTo(to);
return Promise.Resolved();
} else {
return this.animateTo(to, duration: duration??TimeSpan.Zero , curve: curve ?? Curves.ease);
}
}
public abstract ScrollDirection userScrollDirection { get; }
public abstract bool allowImplicitScrolling { get; }

27
Runtime/scheduler/binding.cs


return true;
});
this.debugStack = debugCurrentCallbackStack;
}
else {
} else {
this.debugStack = new StackTrace(2, true);
}

public class SchedulerBinding {
public static SchedulerBinding instance {
get {
D.assert(_instance != null, "Binding.instance is null");
D.assert(_instance != null,
"Binding.instance is null. " +
"This usually happens when there is a callback from outside of UIWidgets. " +
"Try to use \"using (WindowProvider.of(BuildContext).getScope()) { ... }\" to wrap your code.");
return _instance;
}

_instance = null;
}
else {
} else {
D.assert(_instance == null, "Binding.instance is already assigned.");
_instance = value;
}

static SchedulerBinding _instance;
internal static SchedulerBinding _instance;
public SchedulerBinding() {
Window.instance.onBeginFrame += this._handleBeginFrame;

if (rawTimeStamp != null) {
_debugDescribeTimeStamp(
this._currentFrameTimeStamp.Value, frameTimeStampDescription);
}
else {
} else {
frameTimeStampDescription.Append("(warm-up frame)");
}

}
this._removedIds.Clear();
}
finally {
} finally {
this._schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}

foreach (FrameCallback callback in localPostFrameCallbacks) {
this._invokeFrameCallback(callback, this._currentFrameTimeStamp.Value);
}
}
finally {
} finally {
this._schedulerPhase = SchedulerPhase.idle;
D.assert(() => {
if (D.debugPrintEndFrameBanner) {

try {
callback(timeStamp);
}
catch (Exception ex) {
} catch (Exception ex) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: ex,
library: "scheduler library",

});
}
}
}
}

377
Runtime/service/keyboard.cs


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.foundation;
public class KeyboadManager {
interface KeyboardDelegate: IDisposable {
void show();
void hide();
void setEditingState(TextEditingValue value);
void setIMEPos(Offset imeGlobalPos);
void setClient(int client, TextInputConfiguration configuration);
void clearClient();
bool imeRequired();
}
public interface TextInputUpdateListener {
void Update();
}
public interface TextInputOnGUIListener {
void OnGUI();
}
class DefaultKeyboardDelegate : KeyboardDelegate, TextInputOnGUIListener {
int _client;
TextEditingValue _value;
public void show() {
}
public void hide() {
}
public void setEditingState(TextEditingValue value) {
this._value = value;
}
public void setIMEPos(Offset imeGlobalPos) {
var uiWidgetWindowAdapter = Window.instance as UIWidgetWindowAdapter;
if (uiWidgetWindowAdapter != null) {
var screenPos = uiWidgetWindowAdapter.windowPosToScreenPos(imeGlobalPos);
Input.compositionCursorPos = new Vector2(screenPos.dx, screenPos.dy);
}
else { // editor window case
Input.compositionCursorPos = new Vector2(imeGlobalPos.dx, imeGlobalPos.dy);
}
}
public void setClient(int client, TextInputConfiguration configuration) {
this._client = client;
}
public void clearClient() {
this._client = 0;
}
public bool imeRequired() {
return true;
}
public void OnGUI() {
if (TouchScreenKeyboard.isSupported) {
return;
}
if (this._client == 0) {
return;
}
var currentEvent = Event.current;
var oldValue = this._value;
if (currentEvent != null && currentEvent.type == EventType.KeyDown) {
if (currentEvent.keyCode == KeyCode.Backspace) {
if (this._value.selection.isValid) {
this._value = this._value.deleteSelection(true);
}
} else if (currentEvent.character != '\0') {
this._value = this._value.clearCompose();
char ch = currentEvent.character;
if (ch == '\r' || ch == 3) {
ch = '\n';
}
if (ch == '\n') {
Window.instance.run(() => { TextInput._performAction(this._client, TextInputAction.newline); });
}
if (_validateCharacter(ch)) {
this._value = this._value.insert(new string(ch, 1));
}
} else if (!string.IsNullOrEmpty(Input.compositionString)) {
this._value = this._value.compose(Input.compositionString);
}
currentEvent.Use();
}
if (this._value != oldValue) {
Window.instance.run(() => { TextInput._updateEditingState(this._client, this._value); });
}
}
public void Dispose() {
}
static bool _validateCharacter(char ch) {
return ch >= ' ' || ch == '\t' || ch == '\r' || ch == 10 || ch == '\n';
}
}
class UnityTouchScreenKeyboardDelegate : KeyboardDelegate, TextInputUpdateListener {
int _client;
string _lastCompositionString;
TextInputConfiguration _configuration;

bool _screenKeyboardDone;
readonly TextInput _textInput;
public KeyboadManager(TextInput textInput) {
this._textInput = textInput;
}
if (!TouchScreenKeyboard.isSupported) {
return;
}
if (this._keyboard.canSetSelection && this._pendingSelection != null) {
this._keyboard.selection = this._pendingSelection.Value;

if (!this._screenKeyboardDone) {
this._screenKeyboardDone = true;
Window.instance.run(() => {
this._textInput._performAction(this._client,
TextInput._performAction(this._client,
TextInputAction.done);
});
}

this._keyboard.text,
this._keyboard.canGetSelection
? new TextSelection(keyboardSelection.start, keyboardSelection.end)
: this._value.selection
: TextSelection.collapsed(0)
this._textInput._updateEditingState(this._client,
TextInput._updateEditingState(this._client,
this._value);
});
}

public void OnGUI() {
if (TouchScreenKeyboard.isSupported) {
return;
}
if (this._client == 0) {
return;
}
var currentEvent = Event.current;
if (currentEvent != null && currentEvent.type == EventType.KeyDown) {
var action = TextInputUtils.getInputAction(currentEvent);
if (action != null) {
Window.instance.run(() => { this._textInput._performAction(this._client, action.Value); });
}
if (action == null || action == TextInputAction.newline) {
if (currentEvent.keyCode == KeyCode.None) {
this._value = this._value.clearCompose().insert(new string(currentEvent.character, 1));
Window.instance.run(() => { this._textInput._updateEditingState(this._client, this._value); });
}
}
currentEvent.Use();
}
if (!string.IsNullOrEmpty(Input.compositionString) &&
this._lastCompositionString != Input.compositionString) {
this._value = this._value.compose(Input.compositionString);
Window.instance.run(() => { this._textInput._updateEditingState(this._client, this._value); });
}
this._lastCompositionString = Input.compositionString;
}
if (!TouchScreenKeyboard.isSupported) {
return;
}
var secure = this._configuration.obscureText;
var multiline = this._configuration.inputType == TextInputType.multiline;
var autocorrection = this._configuration.autocorrect;

public void clearClient() {
this._client = 0;
}
public bool imeRequired() {
return false;
}
public void setIMEPos(Offset imeGlobalPos) {
}
public void setClient(int client, TextInputConfiguration configuration) {

}
}
}
public bool textInputOnKeyboard() {
return TouchScreenKeyboard.isSupported;
}
static TouchScreenKeyboardType getKeyboardTypeForConfiguration(TextInputConfiguration config) {
var inputType = config.inputType;

return TouchScreenKeyboardType.Default;
}
public void Dispose() {
}
abstract class AbstractUIWidgetsKeyboardDelegate : KeyboardDelegate {
protected AbstractUIWidgetsKeyboardDelegate() {
UIWidgetsMessageManager.instance.
AddChannelMessageDelegate("TextInput", this._handleMethodCall);
}
public void Dispose() {
UIWidgetsMessageManager.instance.
RemoveChannelMessageDelegate("TextInput", this._handleMethodCall);
}
public abstract void show();
public abstract void hide();
public abstract void setEditingState(TextEditingValue value);
public abstract void setIMEPos(Offset imeGlobalPos);
public abstract void setClient(int client, TextInputConfiguration configuration);
public abstract void clearClient();
public virtual bool imeRequired() {
return false;
}
void _handleMethodCall(string method, List<JSONNode> args) {
if (TextInput._currentConnection == null) {
return;
}
int client = args[0].AsInt;
if (client != TextInput._currentConnection._id) {
return;
}
using (TextInput._currentConnection._window.getScope()) {
switch (method) {
case "TextInputClient.updateEditingState":
TextInput._updateEditingState(client, TextEditingValue.fromJson(args[1].AsObject));
break;
case "TextInputClient.performAction":
TextInput._performAction(client, TextInputUtils._toTextInputAction(args[1].Value));
break;
default:
throw new UIWidgetsError($"unknown method ${method}");
}
}
}
}
#if UNITY_WEBGL
class UIWidgetsWebGLKeyboardDelegate : AbstractUIWidgetsKeyboardDelegate {
public override void show() {
Input.imeCompositionMode = IMECompositionMode.On;
}
public override void hide() {
}
public override void setEditingState(TextEditingValue value) {
UIWidgetsTextInputSetTextInputEditingState(value.toJson().ToString());
}
public override void setIMEPos(Offset imeGlobalPos) {
var window = Window.instance as UIWidgetWindowAdapter;
var canvasPos = window.windowPosToScreenPos(imeGlobalPos);
UIWidgetsTextInputSetIMEPos(canvasPos.dx, canvasPos.dy);
}
public override void setClient(int client, TextInputConfiguration configuration) {
WebGLInput.captureAllKeyboardInput = false;
Input.imeCompositionMode = IMECompositionMode.On;
UIWidgetsTextInputSetClient(client, configuration.toJson().ToString());
}
public override void clearClient() {
UIWidgetsTextInputClearTextInputClient();
}
public override bool imeRequired() {
return true;
}
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputSetClient(int client, string configuration);
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputSetTextInputEditingState(string jsonText);
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputClearTextInputClient();
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputSetIMEPos(float x, float y);
}
#endif
#if UNITY_IOS || UNITY_ANDROID
class UIWidgetsTouchScreenKeyboardDelegate : AbstractUIWidgetsKeyboardDelegate {
public override void show() {
UIWidgetsTextInputShow();
}
public override void hide() {
UIWidgetsTextInputHide();
}
public override void setEditingState(TextEditingValue value) {
UIWidgetsTextInputSetTextInputEditingState(value.toJson().ToString());
}
public override void setIMEPos(Offset imeGlobalPos) {
}
public override void setClient(int client, TextInputConfiguration configuration) {
UIWidgetsTextInputSetClient(client, configuration.toJson().ToString());
}
public override void clearClient() {
UIWidgetsTextInputClearTextInputClient();
}
#if UNITY_IOS
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputShow();
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputHide();
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputSetClient(int client, string configuration);
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputSetTextInputEditingState(string jsonText);
[DllImport ("__Internal")]
internal static extern void UIWidgetsTextInputClearTextInputClient();
#elif UNITY_ANDROID
internal static void UIWidgetsTextInputShow() {
using (
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
) {
pluginClass.CallStatic("show");
}
}
internal static void UIWidgetsTextInputHide() {
using (
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
) {
pluginClass.CallStatic("hide");
}
}
internal static void UIWidgetsTextInputSetClient(int client, string configuration) {
using (
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
) {
pluginClass.CallStatic("setClient", client, configuration);
}
}
internal static void UIWidgetsTextInputSetTextInputEditingState(string jsonText) {
using (
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
) {
pluginClass.CallStatic("setEditingState", jsonText);
}
}
internal static void UIWidgetsTextInputClearTextInputClient() {
using (
AndroidJavaClass pluginClass = new AndroidJavaClass("com.unity.uiwidgets.plugin.editing.TextInputPlugin")
) {
pluginClass.CallStatic("clearClient");
}
}
#endif
}
#endif
}

16
Runtime/service/system_chrome.cs


public override int GetHashCode() {
var hashCode = this.systemNavigationBarColor.GetHashCode();
hashCode = (hashCode * 397) ^ this.systemNavigationBarDividerColor.GetHashCode();
hashCode = (hashCode * 397) ^ this.statusBarColor.GetHashCode();
hashCode = (hashCode * 397) ^ this.statusBarBrightness.GetHashCode();
hashCode = (hashCode * 397) ^ this.statusBarIconBrightness.GetHashCode();
hashCode = (hashCode * 397) ^ this.systemNavigationBarIconBrightness.GetHashCode();
hashCode = (hashCode * 397) ^ (this.systemNavigationBarDividerColor != null
? this.systemNavigationBarDividerColor.GetHashCode()
: 0);
hashCode = (hashCode * 397) ^ (this.statusBarColor != null ? this.statusBarColor.GetHashCode() : 0);
hashCode = (hashCode * 397) ^
(this.statusBarBrightness != null ? this.statusBarBrightness.GetHashCode() : 0);
hashCode = (hashCode * 397) ^
(this.statusBarIconBrightness != null ? this.statusBarIconBrightness.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.systemNavigationBarIconBrightness != null
? this.systemNavigationBarIconBrightness.GetHashCode()
: 0);
return hashCode;
}

27
Runtime/service/text_formatter.cs


(substring) => this.blacklistedPattern.Replace(substring, this.replacementString));
}
}
public class LengthLimitingTextInputFormatter : TextInputFormatter {
public LengthLimitingTextInputFormatter(int? maxLength) {
D.assert(maxLength == null || maxLength > 0);
this.maxLength = maxLength;
}
public readonly int? maxLength;
public override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
if (this.maxLength != null && newValue.text.Length > this.maxLength) {
TextSelection newSelection = newValue.selection.copyWith(
baseOffset: Math.Min(newValue.selection.start, this.maxLength.Value),
extentOffset: Math.Min(newValue.selection.end, this.maxLength.Value)
);
string truncated = newValue.text.Substring(0, this.maxLength.Value);
return new TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty
);
}
return newValue;
}
}
static class Util {
internal static TextEditingValue _selectionAwareTextManipulation(TextEditingValue value,

305
Runtime/service/text_input.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;

"text", "multiline", "number", "phone", "datetime", "emailAddress", "url"
};
public Dictionary<string, object> toJson() {
return new Dictionary<string, object>() {
{"name", this._name},
{"signed", this.signed},
{"decimal", this.decimalNum}
};
public JSONNode toJson() {
JSONObject jsonObject = new JSONObject();
jsonObject["name"] = this._name;
jsonObject["signed"] = this.signed;
jsonObject["decimal"] = this.decimalNum;
return jsonObject;
}
string _name {

}
}
static partial class TextInputUtils {
internal static TextAffinity? _toTextAffinity(string affinity) {
switch (affinity) {
case "TextAffinity.downstream":
return TextAffinity.downstream;
case "TextAffinity.upstream":
return TextAffinity.upstream;
}
return null;
}
internal static TextInputAction _toTextInputAction(string action) {
switch (action) {
case "TextInputAction.none":
return TextInputAction.none;
case "TextInputAction.unspecified":
return TextInputAction.unspecified;
case "TextInputAction.go":
return TextInputAction.go;
case "TextInputAction.search":
return TextInputAction.search;
case "TextInputAction.send":
return TextInputAction.send;
case "TextInputAction.next":
return TextInputAction.next;
case "TextInputAction.previuos":
return TextInputAction.previous;
case "TextInputAction.continue_action":
return TextInputAction.continueAction;
case "TextInputAction.join":
return TextInputAction.join;
case "TextInputAction.route":
return TextInputAction.route;
case "TextInputAction.emergencyCall":
return TextInputAction.emergencyCall;
case "TextInputAction.done":
return TextInputAction.done;
case "TextInputAction.newline":
return TextInputAction.newline;
}
throw new UIWidgetsError("Unknown text input action: $action");
}
}
static JSONNode defaultIndexNode = new JSONNumber(-1);
public TextEditingValue(string text = "", TextSelection selection = null, TextRange composing = null) {
this.text = text;
this.selection = selection ?? TextSelection.collapsed(-1);

public static TextEditingValue fromJson(JSONObject json) {
TextAffinity? affinity =
TextInputUtils._toTextAffinity(json["selectionAffinity"].Value);
return new TextEditingValue(
text: json["text"].Value,
selection: new TextSelection(
baseOffset: json.GetValueOrDefault("selectionBase", defaultIndexNode).AsInt,
extentOffset: json.GetValueOrDefault("selectionExtent", defaultIndexNode).AsInt,
affinity: affinity != null ? affinity.Value : TextAffinity.downstream,
isDirectional: json["selectionIsDirectional"].AsBool
),
composing: new TextRange(
start: json.GetValueOrDefault("composingBase", defaultIndexNode).AsInt,
end: json.GetValueOrDefault("composingExtent", defaultIndexNode).AsInt
)
);
}
public TextEditingValue copyWith(string text = null, TextSelection selection = null,
TextRange composing = null) {
return new TextEditingValue(

return this;
}
newText = this.selection.textBefore(this.text) + text + this.selection.textAfter(this.text);
newSelection = TextSelection.collapsed(this.selection.start + text.Length);
var selection = this.selection;
if (selection.start < 0) {
selection = TextSelection.collapsed(0, this.selection.affinity);
}
newText = selection.textBefore(this.text) + text + selection.textAfter(this.text);
newSelection = TextSelection.collapsed(selection.start + text.Length);
return new TextEditingValue(
text: newText, selection: newSelection, composing: TextRange.empty
);

return this.copyWith(
text: this.text.Substring(0, this.selection.start - 1) + this.selection.textAfter(this.text),
selection: TextSelection.collapsed(this.selection.start - 1));
selection: TextSelection.collapsed(this.selection.start - 1),
composing: TextRange.empty);
}
if (this.selection.start >= this.text.Length) {

return this.copyWith(text: this.text.Substring(0, this.selection.start) +
this.text.Substring(this.selection.start + 1));
this.text.Substring(this.selection.start + 1),
composing: TextRange.empty);
return this.copyWith(text: newText, selection: TextSelection.collapsed(this.selection.start));
return this.copyWith(text: newText, selection: TextSelection.collapsed(this.selection.start),
composing: TextRange.empty);
}
}

public override string ToString() {
return $"Text: {this.text}, Selection: {this.selection}, Composing: {this.composing}";
}
public JSONNode toJson() {
var json = new JSONObject();
json["text"] = this.text;
json["selectionBase"] = this.selection.baseOffset;
json["selectionExtent"] = this.selection.extentOffset;
json["selectionAffinity"] = this.selection.affinity.ToString();
json["selectionIsDirectional"] = this.selection.isDirectional;
json["composingBase"] = this.composing.start;
json["composingExtent"] = this.composing.end;
return json;
}
}
public interface TextSelectionDelegate {

join,
route,
emergencyCall,
newline,
moveLeft,
moveRight,
moveUp,
moveDown,
moveLineStart,
moveLineEnd,
moveTextStart,
moveTextEnd,
movePageUp,
movePageDown,
moveGraphicalLineStart,
moveGraphicalLineEnd,
moveWordLeft,
moveWordRight,
moveParagraphForward,
moveParagraphBackward,
moveToStartOfNextWord,
moveToEndOfPreviousWord,
selectLeft,
selectRight,
selectUp,
selectDown,
selectTextStart,
selectTextEnd,
selectPageUp,
selectPageDown,
expandSelectGraphicalLineStart,
expandSelectGraphicalLineEnd,
selectGraphicalLineStart,
selectGraphicalLineEnd,
selectWordLeft,
selectWordRight,
selectToEndOfPreviousWord,
selectToStartOfNextWord,
selectParagraphBackward,
selectParagraphForward,
delete,
backspace,
deleteWordBack,
deleteWordForward,
deleteLineBack,
cut,
copy,
paste,
selectAll,
selectNone,
scrollStart,
scrollEnd,
scrollPageUp,
scrollPageDown,
newline
}
public enum TextCapitalization {
words,
sentences,
characters,
none
public class TextInputConfiguration {
class TextInputConfiguration {
bool obscureText = false, bool autocorrect = true, TextInputAction inputAction = TextInputAction.done) {
bool obscureText = false, bool autocorrect = true, TextInputAction inputAction = TextInputAction.done,
Brightness keyboardAppearance = Brightness.light, TextCapitalization textCapitalization = TextCapitalization.none,
bool unityTouchKeyboard = false) {
this.textCapitalization = textCapitalization;
this.keyboardAppearance = keyboardAppearance;
this.unityTouchKeyboard = unityTouchKeyboard;
}
public readonly TextInputType inputType;

public readonly TextCapitalization textCapitalization;
public readonly Brightness keyboardAppearance;
public readonly bool unityTouchKeyboard;
public Dictionary<string, object> toJson() {
return new Dictionary<string, object>() {
{"inputType", this.inputType.toJson()},
{"obscureText", this.obscureText},
{"autocorrect", this.autocorrect},
{"inputAction", this.inputAction.ToString()}
};
public JSONNode toJson() {
var json = new JSONObject();
json["inputType"] = this.inputType.toJson();
json["obscureText"] = this.obscureText;
json["autocorrect"] = this.autocorrect;
json["inputAction"] = $"TextInputAction.{this.inputAction.ToString()}";
json["unityTouchKeyboard"] = this.unityTouchKeyboard;
json["textCapitalization"] = $"TextCapitalization.{this.textCapitalization.ToString()}";
json["keyboardAppearance"] = $"Brightness.{this.keyboardAppearance.ToString()}";
return json;
internal TextInputConnection(TextInputClient client, TextInput textInput) {
internal TextInputConnection(TextInputClient client) {
D.assert(textInput != null);
this._window = Window.instance;
this._textInput = textInput;
get { return this._textInput._currentConnection == this; }
get { return TextInput._currentConnection == this; }
this._textInput.keyboardManager.setEditingState(value);
TextInput.keyboardDelegate.setEditingState(value);
public void setCompositionCursorPos(float x, float y) {
public void setIMEPos(Offset imeGlobalPos) {
this._textInput.setCompositionCursorPos(x, y);
D.assert(imeGlobalPos != null);
D.assert(this.imeRequired());
TextInput.keyboardDelegate.setIMEPos(imeGlobalPos);
public bool imeRequired() {
return TextInput.keyboardDelegate != null && TextInput.keyboardDelegate.imeRequired();
}
this._textInput.keyboardManager.clearClient();
this._textInput._currentConnection = null;
TextInput.keyboardDelegate.clearClient();
TextInput._currentConnection = null;
this._textInput._scheduleHide();
TextInput._scheduleHide();
}
D.assert(!this.attached);

D.assert(this.attached);
Input.imeCompositionMode = IMECompositionMode.On;
this._textInput.keyboardManager.show();
TextInput.keyboardDelegate.show();
internal readonly TextInput _textInput;
internal readonly Window _window;
public class TextInput {
internal TextInputConnection _currentConnection;
class TextInput {
static internal TextInputConnection _currentConnection;
public readonly KeyboadManager keyboardManager;
static internal KeyboardDelegate keyboardDelegate;
this.keyboardManager = new KeyboadManager(this);
public TextInputConnection attach(TextInputClient client, TextInputConfiguration configuration) {
public static TextInputConnection attach(TextInputClient client, TextInputConfiguration configuration) {
var connection = new TextInputConnection(client, this);
this.keyboardManager.setClient(connection._id, configuration);
this._currentConnection = connection;
var connection = new TextInputConnection(client);
_currentConnection = connection;
if (keyboardDelegate != null) {
keyboardDelegate.Dispose();
}
if (Application.isEditor) {
keyboardDelegate = new DefaultKeyboardDelegate();
} else {
#if UNITY_IOS || UNITY_ANDROID
if (configuration.unityTouchKeyboard) {
keyboardDelegate = new UnityTouchScreenKeyboardDelegate();
}
else {
keyboardDelegate = new UIWidgetsTouchScreenKeyboardDelegate();
}
#elif UNITY_WEBGL
keyboardDelegate = new UIWidgetsWebGLKeyboardDelegate();
#else
keyboardDelegate = new DefaultKeyboardDelegate();
#endif
}
keyboardDelegate.setClient(connection._id, configuration);
public void setCompositionCursorPos(float x, float y) {
Input.compositionCursorPos = new Vector2(x, y);
internal static void Update() {
if (_currentConnection != null && _currentConnection._window == Window.instance) {
(keyboardDelegate as TextInputUpdateListener)?.Update();
}
internal void _updateEditingState(int client, TextEditingValue value) {
if (this._currentConnection == null) {
internal static void OnGUI() {
if (_currentConnection != null && _currentConnection._window == Window.instance) {
(keyboardDelegate as TextInputOnGUIListener)?.OnGUI();
}
}
internal static void _updateEditingState(int client, TextEditingValue value) {
if (_currentConnection == null) {
if (client != this._currentConnection._id) {
if (client != _currentConnection._id) {
this._currentConnection._client.updateEditingValue(value);
_currentConnection._client.updateEditingValue(value);
internal void _performAction(int client, TextInputAction action) {
if (this._currentConnection == null) {
internal static void _performAction(int client, TextInputAction action) {
if (_currentConnection == null) {
if (client != this._currentConnection._id) {
if (client != _currentConnection._id) {
this._currentConnection._client.performAction(action);
_currentConnection._client.performAction(action);
bool _hidePending = false;
static bool _hidePending = false;
internal void _scheduleHide() {
if (this._hidePending) {
static internal void _scheduleHide() {
if (_hidePending) {
this._hidePending = true;
_hidePending = true;
this._hidePending = false;
if (this._currentConnection == null) {
this.keyboardManager.hide();
_hidePending = false;
if (_currentConnection == null) {
keyboardDelegate.hide();
}
}
}
}

60
Runtime/ui/compositing.cs


using System;
using System;
using UnityEngine;
namespace Unity.UIWidgets.ui {
public class SceneBuilder {

public Layer pushOpacity(int alpha, Offset offset = null) {
offset = offset ?? Offset.zero;
var layer = new OpacityLayer();
layer.alpha = alpha;
layer.offset = offset;

public Layer pushBackdropFilter(ImageFilter filter) {
var layer = new BackdropFilterLayer();
layer.filter = filter;
this._pushLayer(layer);
return layer;
}
public void addRetained(Layer layer) {
if (this._currentLayer == null) {
return;

bool isComplexHint = false, bool willChangeHint = false) {
D.assert(offset != null);
D.assert(picture != null);
if (this._currentLayer == null) {
return;
}

layer.isComplex = isComplexHint;
layer.willChange = willChangeHint;
this._currentLayer.add(layer);
}
public void addTexture(
Texture texture,
Offset offset,
float width,
float height,
bool freeze) {
if (this._currentLayer == null) {
return;
}
var layer = new TextureLayer();
layer.offset = offset;
layer.size = new Size(width, height);
layer.texture = texture;
layer.freeze = freeze;
this._currentLayer.add(layer);
}
public void addPerformanceOverlay(int enabledOptions, Rect bounds) {
if (this._currentLayer == null) {
return;
}
var layer = new PerformanceOverlayLayer(enabledOptions);
layer.paintBounds = Rect.fromLTRB(
bounds.left,
bounds.top,
bounds.right,
bounds.bottom
);
this._currentLayer.add(layer);
}
public Layer pushPhysicalShape(Path path, float elevation, Color color, Color shadowColor, Clip clipBehavior) {
var layer = new PhysicalShapeLayer(clipBehavior);
layer.path = path;
layer.elevation = elevation;
layer.color = color;
layer.shadowColor = shadowColor;
layer.devicePixelRatio = Window.instance.devicePixelRatio;
this._pushLayer(layer);
return layer;
}
}

103
Runtime/ui/geometry.cs


namespace Unity.UIWidgets.ui {
public static class MathUtils {
const float _valueNearlyZero = 1f / (1 << 12);
public static bool isConvexPolygon(Offset[] polygonVerts, int polygonSize) {
if (polygonSize < 3) {
return false;
}
float lastArea = 0;
float lastPerpDot = 0;
int prevIndex = polygonSize - 1;
int currIndex = 0;
int nextIndex = 1;
Offset origin = polygonVerts[0];
Vector2 v0 = (polygonVerts[currIndex] - polygonVerts[prevIndex]).toVector();
Vector2 v1 = (polygonVerts[nextIndex] - polygonVerts[currIndex]).toVector();
Vector2 w0 = (polygonVerts[currIndex] - origin).toVector();
Vector2 w1 = (polygonVerts[nextIndex] - origin).toVector();
for (int i = 0; i < polygonSize; i++) {
if (!polygonVerts[i].isFinite) {
return false;
}
float perpDot = v0.cross(v1);
if (lastPerpDot * perpDot < 0) {
return false;
}
if (0 != perpDot) {
lastPerpDot = perpDot;
}
float quadArea = w0.cross(w1);
if (quadArea * lastArea < 0) {
return false;
}
if (0 != quadArea) {
lastArea = quadArea;
}
prevIndex = currIndex;
currIndex = nextIndex;
nextIndex = (currIndex + 1) % polygonSize;
v0 = v1;
v1 = (polygonVerts[nextIndex] - polygonVerts[currIndex]).toVector();
w0 = w1;
w1 = (polygonVerts[nextIndex] - origin).toVector();
}
return true;
}
public static float cross(this Vector2 vector1, Vector2 vector2) {
return Vector3.Cross(new Vector3(vector1.x, vector1.y, 0f), new Vector3(vector2.x, vector2.y, 0f)).z;
}
public static bool valueNearlyZero(this float x, float? tolerance = null) {
tolerance = tolerance ?? _valueNearlyZero;
return Mathf.Abs(x) <= tolerance;
}
public static float clamp(this float value, float min, float max) {
if (value < min) {
value = min;

}
return value;
}
public static int abs(this int value) {
return Mathf.Abs(value);
}
public static float abs(this float value) {

this.left * scaleX, this.top * scaleY.Value,
this.right * scaleX, this.bottom * scaleY.Value);
}
public Rect outset(float dx, float dy) {
return new Rect(this.left - dx, this.top - dy, this.right + dx, this.bottom + dy);
}
public Offset[] toQuad() {
Offset[] dst = new Offset[4];
dst[0] = new Offset(this.left, this.top);
dst[1] = new Offset(this.right, this.top);
dst[2] = new Offset(this.right, this.bottom);
dst[3] = new Offset(this.left, this.bottom);
return dst;
}
public Rect inflate(float delta) {
return fromLTRB(this.left - delta, this.top - delta, this.right + delta, this.bottom + delta);

Mathf.Ceil(this.right), Mathf.Ceil(this.bottom));
}
public Rect roundOut(float devicePixelRatio) {
return fromLTRB(
Mathf.Floor(this.left * devicePixelRatio) / devicePixelRatio,
Mathf.Floor(this.top * devicePixelRatio) / devicePixelRatio,
Mathf.Ceil(this.right * devicePixelRatio) / devicePixelRatio,
Mathf.Ceil(this.bottom * devicePixelRatio) / devicePixelRatio);
}
}
public Rect normalize() {
if (this.left <= this.right && this.top <= this.bottom) {
return this;
}
return fromLTRB(
Mathf.Min(this.left, this.right),
Mathf.Min(this.top, this.bottom),
Mathf.Max(this.left, this.right),
Mathf.Max(this.top, this.bottom)
);
}
public static Rect lerp(Rect a, Rect b, float t) {

14
Runtime/ui/matrix.cs


src.top + ty,
src.right + tx,
src.bottom + ty
);
).normalize();
return true;
}

src.top * sy + ty,
src.right * sx + tx,
src.bottom * sy + ty
);
).normalize();
}
public Offset[] mapRectToQuad(Rect rect) {
Offset[] dst = rect.toQuad();
this.mapPoints(dst, dst);
return dst;
return true;
}
if (ReferenceEquals(a, b)) {
return true;
}

47
Runtime/ui/painting/canvas.cs


using System;
using Unity.UIWidgets.flow;
using UnityEngine;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui {
public interface Canvas {

void drawRect(Rect rect, Paint paint);
void drawShadow(Path path, Color color, float elevation, bool transparentOccluder);
void drawRRect(RRect rect, Paint paint);
void drawDRRect(RRect outer, RRect inner, Paint paint);

void drawTextBlob(TextBlob textBlob, Offset offset, Paint paint);
void drawParagraph(Paragraph paragraph, Offset offset);
void flush();
void reset();

});
}
public void drawShadow(Path path, Color color, float elevation, bool transparentOccluder) {
float dpr = Window.instance.devicePixelRatio;
PhysicalShapeLayer.drawShadow(this, path, color, elevation, transparentOccluder, dpr);
}
public void drawRect(Rect rect, Paint paint) {
if (rect.size.isEmpty) {
return;

public void drawArc(Rect rect, float startAngle, float sweepAngle, bool useCenter, Paint paint) {
var path = new Path();
//path.(c.dx, c.dy, radius);
if (useCenter) {
var center = rect.center;
path.moveTo(center.dx, center.dy);
}
bool forceMoveTo = !useCenter;
while (sweepAngle <= -Mathf.PI * 2) {
path.addArc(rect, startAngle, -Mathf.PI, forceMoveTo);
startAngle -= Mathf.PI;
path.addArc(rect, startAngle, -Mathf.PI, false);
startAngle -= Mathf.PI;
forceMoveTo = false;
sweepAngle += Mathf.PI * 2;
}
while (sweepAngle >= Mathf.PI * 2) {
path.addArc(rect, startAngle, Mathf.PI, forceMoveTo);
startAngle += Mathf.PI;
path.addArc(rect, startAngle, Mathf.PI, false);
startAngle += Mathf.PI;
forceMoveTo = false;
sweepAngle -= Mathf.PI * 2;
}
path.addArc(rect, startAngle, sweepAngle, forceMoveTo);
if (useCenter) {
path.close();
}
this._recorder.addDrawCmd(new DrawPath {
path = path,

offset = offset,
paint = new Paint(paint),
});
}
public void drawParagraph(Paragraph paragraph, Offset offset) {
D.assert(paragraph != null);
D.assert(PaintingUtils._offsetIsValid(offset));
paragraph.paint(this, offset);
}
public virtual void flush() {

266
Runtime/ui/painting/canvas_impl.cs


readonly List<RenderLayer> _layers = new List<RenderLayer>();
RenderLayer _currentLayer;
Rect _lastScissor;
public PictureFlusher(RenderTexture renderTexture, float devicePixelRatio, MeshPool meshPool) {
D.assert(renderTexture);

layerPaint = paint,
};
parentLayer.layers.Add(layer);
parentLayer.addLayer(layer);
if (paint.backdrop != null) {
if (paint.backdrop is _BlurImageFilter) {
var filter = (_BlurImageFilter) paint.backdrop;
if (!(filter.sigmaX == 0 && filter.sigmaY == 0)) {
var points = new[] {bounds.topLeft, bounds.bottomLeft, bounds.bottomRight, bounds.topRight};
state.matrix.mapPoints(points);
var parentBounds = parentLayer.layerBounds;
for (int i = 0; i < 4; i++) {
points[i] = new Offset(
(points[i].dx - parentBounds.left) / parentBounds.width,
(points[i].dy - parentBounds.top) / parentBounds.height
);
}
var mesh = ImageMeshGenerator.imageMesh(
null,
points[0], points[1], points[2], points[3],
bounds);
var renderDraw = CanvasShader.texRT(layer, layer.layerPaint, mesh, parentLayer);
layer.draws.Add(renderDraw);
var blurLayer = this._createBlurLayer(layer, filter.sigmaX, filter.sigmaY, layer);
var blurMesh = ImageMeshGenerator.imageMesh(null, Rect.one, bounds);
layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer));
}
} else if (paint.backdrop is _MatrixImageFilter) {
var filter = (_MatrixImageFilter) paint.backdrop;
if (!filter.transform.isIdentity()) {
layer.filterMode = filter.filterMode;
var points = new[] {bounds.topLeft, bounds.bottomLeft, bounds.bottomRight, bounds.topRight};
state.matrix.mapPoints(points);
var parentBounds = parentLayer.layerBounds;
for (int i = 0; i < 4; i++) {
points[i] = new Offset(
(points[i].dx - parentBounds.left) / parentBounds.width,
(points[i].dy - parentBounds.top) / parentBounds.height
);
}
var matrix = Matrix3.makeTrans(-bounds.left, -bounds.top);
matrix.postConcat(filter.transform);
matrix.postTranslate(bounds.left, bounds.top);
var mesh = ImageMeshGenerator.imageMesh(
matrix,
points[0], points[1], points[2], points[3],
bounds);
var renderDraw = CanvasShader.texRT(layer, layer.layerPaint, mesh, parentLayer);
layer.draws.Add(renderDraw);
}
}
}
}
void _restore() {

}
void _tryAddScissor(RenderLayer layer, Rect scissor) {
if (scissor == layer.lastScissor) {
if (scissor == this._lastScissor) {
layer.draws.Add(new RenderScissor {
layer.draws.Add(new CmdScissor {
layer.lastScissor = scissor;
this._lastScissor = scissor;
if (queryBounds == null || queryBounds.isEmpty) {
return false;
}
var layer = this._currentLayer;
var layerBounds = layer.layerBounds;
ReducedClip reducedClip = new ReducedClip(layer.clipStack, layerBounds, queryBounds);

} else {
layer.ignoreClip = false;
var boundsMesh = new MeshMesh(reducedClip.scissor);
// need to inflate a bit to make sure all area is cleared.
var inflatedScissor = reducedClip.scissor.inflate(this._fringeWidth);
var boundsMesh = new MeshMesh(inflatedScissor);
layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh));
foreach (var maskElement in reducedClip.maskElements) {

filterMode = FilterMode.Bilinear,
};
parentLayer.layers.Add(maskLayer);
parentLayer.addLayer(maskLayer);
this._layers.Add(maskLayer);
this._currentLayer = maskLayer;

return maskLayer;
}
RenderLayer _createBlurLayer(RenderLayer maskLayer, float sigma, RenderLayer parentLayer) {
sigma = BlurUtils.adjustSigma(sigma, out var scaleFactor, out var radius);
RenderLayer _createBlurLayer(RenderLayer maskLayer, float sigmaX, float sigmaY, RenderLayer parentLayer) {
sigmaX = BlurUtils.adjustSigma(sigmaX, out var scaleFactorX, out var radiusX);
sigmaY = BlurUtils.adjustSigma(sigmaY, out var scaleFactorY, out var radiusY);
var textureWidth = Mathf.CeilToInt((float) maskLayer.width / scaleFactor);
var textureWidth = Mathf.CeilToInt((float) maskLayer.width / scaleFactorX);
var textureHeight = Mathf.CeilToInt((float) maskLayer.height / scaleFactor);
var textureHeight = Mathf.CeilToInt((float) maskLayer.height / scaleFactorY);
if (textureHeight < 1) {
textureHeight = 1;
}

filterMode = FilterMode.Bilinear,
};
parentLayer.layers.Add(blurXLayer);
parentLayer.addLayer(blurXLayer);
var blurYLayer = new RenderLayer {
rtID = Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count),

filterMode = FilterMode.Bilinear,
};
parentLayer.layers.Add(blurYLayer);
parentLayer.addLayer(blurYLayer);
var kernel = BlurUtils.get1DGaussianKernel(sigma, radius);
var kernelX = BlurUtils.get1DGaussianKernel(sigmaX, radiusX);
var kernelY = BlurUtils.get1DGaussianKernel(sigmaY, radiusY);
radius, new Vector2(1f / textureWidth, 0), kernel));
radiusX, new Vector2(1f / textureWidth, 0), kernelX));
radius, new Vector2(0, -1f / textureHeight), kernel));
radiusY, new Vector2(0, -1f / textureHeight), kernelY));
return blurYLayer;
}

var maskLayer = this._createMaskLayer(layer, maskBounds, drawAction, paint);
var blurLayer = this._createBlurLayer(maskLayer, sigma, layer);
var blurLayer = this._createBlurLayer(maskLayer, sigma, sigma, layer);
var blurMesh = ImageMeshGenerator.imageMesh(null, Rect.one, maskBounds);
if (!this._applyClip(blurMesh.bounds)) {

var matrix = new Matrix3(state.matrix);
matrix.preTranslate(offset.dx, offset.dy);
var mesh = MeshGenerator.generateMesh(textBlob, scale)?.transform(matrix);
if (mesh == null) {
return;
}
var mesh = new TextBlobMesh(textBlob, scale, matrix);
var font = FontManager.instance.getOrCreate(textBlob.style.fontFamily).font;
// request font texture so text mesh could be generated correctly
var style = textBlob.style;
var font = FontManager.instance.getOrCreate(textBlob.style.fontFamily, style.fontWeight, style.fontStyle).font;
var fontSizeToLoad = Mathf.CeilToInt(style.UnityFontSize * scale);
var subText = textBlob.text.Substring(textBlob.textOffset, textBlob.textSize);
font.RequestCharactersInTextureSafe(subText, fontSizeToLoad, style.UnityFontStyle);
if (!this._applyClip(mesh.bounds)) {
if (!this._applyClip(matrix.mapRect(textBlob.bounds))) {
return;
}

if (paint.maskFilter != null && paint.maskFilter.sigma != 0) {
this._drawWithMaskFilter(mesh.bounds, drawMesh, paint, paint.maskFilter);
this._drawWithMaskFilter(textBlob.bounds, drawMesh, paint, paint.maskFilter);
return;
}

public void flush(Picture picture) {
this._reset();
this._drawPicture(picture, false);
D.assert(this._layers.Count == 1);

}
void _drawLayer(RenderLayer layer, CommandBuffer cmdBuf) {
foreach (var subLayer in layer.layers) {
var desc = new RenderTextureDescriptor(
subLayer.width, subLayer.height,
RenderTextureFormat.Default, 24) {
useMipMap = false,
autoGenerateMips = false,
};
if (layer.rtID == 0) {
cmdBuf.SetRenderTarget(this._renderTexture);
cmdBuf.ClearRenderTarget(true, true, UnityEngine.Color.clear);
}
else {
cmdBuf.SetRenderTarget(layer.rtID);
cmdBuf.ClearRenderTarget(true, true, UnityEngine.Color.clear);
}
foreach (var cmdObj in layer.draws) {
switch (cmdObj) {
case CmdLayer cmd:
var subLayer = cmd.layer;
var desc = new RenderTextureDescriptor(
subLayer.width, subLayer.height,
RenderTextureFormat.Default, 24) {
useMipMap = false,
autoGenerateMips = false,
};
if (QualitySettings.antiAliasing != 0) {
desc.msaaSamples = QualitySettings.antiAliasing;
}
if (QualitySettings.antiAliasing != 0) {
desc.msaaSamples = QualitySettings.antiAliasing;
}
cmdBuf.GetTemporaryRT(subLayer.rtID, desc, subLayer.filterMode);
this._drawLayer(subLayer, cmdBuf);
}
if (layer.rtID == 0) {
cmdBuf.SetRenderTarget(this._renderTexture,
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
cmdBuf.ClearRenderTarget(true, true, UnityEngine.Color.clear);
}
else {
cmdBuf.SetRenderTarget(layer.rtID,
RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
cmdBuf.ClearRenderTarget(true, true, UnityEngine.Color.clear);
}
cmdBuf.GetTemporaryRT(subLayer.rtID, desc, subLayer.filterMode);
this._drawLayer(subLayer, cmdBuf);
if (layer.rtID == 0) {
cmdBuf.SetRenderTarget(this._renderTexture);
}
else {
cmdBuf.SetRenderTarget(layer.rtID);
}
foreach (var cmdObj in layer.draws) {
switch (cmdObj) {
case RenderDraw cmd:
break;
case CmdDraw cmd:
cmdBuf.SetGlobalTexture(RenderDraw.texId, cmd.layer.rtID);
if (cmd.layer.rtID == 0) {
cmdBuf.SetGlobalTexture(CmdDraw.texId, this._renderTexture);
} else {
cmdBuf.SetGlobalTexture(CmdDraw.texId, cmd.layer.rtID);
}
}
D.assert(cmd.meshObj == null);

// clear triangles first in order to bypass validation in SetVertices.
cmd.meshObj.SetTriangles((int[]) null, 0, false);
cmd.meshObj.SetVertices(cmd.mesh.vertices);
cmd.meshObj.SetTriangles(cmd.mesh.triangles, 0, false);
cmd.meshObj.SetUVs(0, cmd.mesh.uv);
MeshMesh mesh = cmd.mesh;
if (cmd.textMesh != null) {
mesh = cmd.textMesh.resovleMesh();
}
if (mesh == null) {
continue;
}
D.assert(mesh.vertices.Count > 0);
cmd.meshObj.SetVertices(mesh.vertices);
cmd.meshObj.SetTriangles(mesh.triangles, 0, false);
cmd.meshObj.SetUVs(0, mesh.uv);
if (cmd.mesh.matrix == null) {
cmd.properties.SetFloatArray(RenderDraw.matId, RenderDraw.idMat3.fMat);
if (mesh.matrix == null) {
cmd.properties.SetFloatArray(CmdDraw.matId, CmdDraw.idMat3.fMat);
cmd.properties.SetFloatArray(RenderDraw.matId, cmd.mesh.matrix.fMat);
cmd.properties.SetFloatArray(CmdDraw.matId, mesh.matrix.fMat);
cmdBuf.DrawMesh(cmd.meshObj, RenderDraw.idMat, cmd.material, 0, cmd.pass, cmd.properties);
cmdBuf.DrawMesh(cmd.meshObj, CmdDraw.idMat, cmd.material, 0, cmd.pass, cmd.properties);
cmdBuf.SetGlobalTexture(RenderDraw.texId, BuiltinRenderTextureType.None);
cmdBuf.SetGlobalTexture(CmdDraw.texId, BuiltinRenderTextureType.None);
case RenderScissor cmd:
case CmdScissor cmd:
if (cmd.deviceScissor == null) {
cmdBuf.DisableScissorRect();
} else {

void _clearLayer(RenderLayer layer) {
foreach (var cmdObj in layer.draws) {
switch (cmdObj) {
case RenderDraw cmd:
case CmdDraw cmd:
if (cmd.meshObjCreated) {
this._meshPool.returnMesh(cmd.meshObj);
cmd.meshObj = null;

public readonly ClipStack clipStack = new ClipStack();
public uint lastClipGenId;
public Rect lastClipBounds;
public Rect lastScissor;
public bool ignoreClip;
public bool ignoreClip = true;
Vector4? _viewport;

this.currentState = new State();
this.states.Add(this.currentState);
}
public void addLayer(RenderLayer layer) {
this.layers.Add(layer);
this.draws.Add(new CmdLayer {layer = layer});
}
}
internal class State {

float? _scale;
Matrix3 _invMatrix;
public State(Matrix3 matrix = null, float? scale = null) {
public State(Matrix3 matrix = null, float? scale = null, Matrix3 invMatrix = null) {
this._invMatrix = invMatrix;
this._matrix = value;
this._matrix = value ?? _id;
this._invMatrix = null;
}
}

return this._scale.Value;
}
}
public Matrix3 invMatrix {
get {
if (this._invMatrix == null) {
this._invMatrix = Matrix3.I();
this._matrix.invert(this._invMatrix);
}
return this._invMatrix;
}
}
return new State(this._matrix, this._scale);
return new State(this._matrix, this._scale, this._invMatrix);
internal class RenderDraw {
internal class CmdLayer {
public RenderLayer layer;
}
internal class CmdDraw {
public TextBlobMesh textMesh;
public int pass;
public MaterialPropertyBlock properties;
public RenderLayer layer;

public static readonly int matId = Shader.PropertyToID("_mat");
}
internal class RenderScissor {
internal class CmdScissor {
public Rect deviceScissor;
}
}

10, 11, 14, 11, 15, 14,
};
public static MeshMesh imageMesh(Matrix3 matrix,
Offset srcTL, Offset srcBL, Offset srcBR, Offset srcTR,
Rect dst) {
var vertices = new List<Vector3>(4);
var uv = new List<Vector2>(4);
vertices.Add(new Vector2(dst.left, dst.top));
uv.Add(new Vector2(srcTL.dx, 1.0f - srcTL.dy));
vertices.Add(new Vector2(dst.left, dst.bottom));
uv.Add(new Vector2(srcBL.dx, 1.0f - srcBL.dy));
vertices.Add(new Vector2(dst.right, dst.bottom));
uv.Add(new Vector2(srcBR.dx, 1.0f - srcBR.dy));
vertices.Add(new Vector2(dst.right, dst.top));
uv.Add(new Vector2(srcTR.dx, 1.0f - srcTR.dy));
return new MeshMesh(matrix, vertices, _imageTriangles, uv);
}
public static MeshMesh imageMesh(Matrix3 matrix, Rect src, Rect dst) {
var vertices = new List<Vector3>(4);
var uv = new List<Vector2>(4);

119
Runtime/ui/painting/canvas_shader.cs


);
}
static void _getShaderPassAndProps(Vector4 viewport, Matrix3 ctm, Paint paint, float alpha,
static Matrix3 _getShaderMatBase(PictureFlusher.State state, Matrix3 meshMatrix) {
if (state.matrix == meshMatrix) {
return Matrix3.I();
}
if (meshMatrix == null) {
return state.invMatrix;
}
return Matrix3.concat(state.invMatrix, meshMatrix);
}
static void _getShaderPassAndProps(
PictureFlusher.RenderLayer layer, Paint paint, MeshMesh mesh, float alpha,
Vector4 viewport = layer.viewport;
props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
props.SetFloat("_alpha", alpha);

return;
case _LinearGradient linear:
pass = 1;
props.SetMatrix("_shaderMat", linear.getGradientMat(ctm).toMatrix4x4());
props.SetMatrix("_shaderMat", linear.getGradientMat(
_getShaderMatBase(layer.currentState, mesh.matrix)).toMatrix4x4());
props.SetTexture("_shaderTex", linear.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(linear.leftColor));
props.SetVector("_rightColor", _colorToVector4(linear.rightColor));

pass = 2;
props.SetMatrix("_shaderMat", radial.getGradientMat(ctm).toMatrix4x4());
props.SetMatrix("_shaderMat", radial.getGradientMat(
_getShaderMatBase(layer.currentState, mesh.matrix)).toMatrix4x4());
props.SetTexture("_shaderTex", radial.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(radial.leftColor));
props.SetVector("_rightColor", _colorToVector4(radial.rightColor));

pass = 3;
props.SetMatrix("_shaderMat", sweep.getGradientMat(ctm).toMatrix4x4());
props.SetMatrix("_shaderMat", sweep.getGradientMat(
_getShaderMatBase(layer.currentState, mesh.matrix)).toMatrix4x4());
props.SetTexture("_shaderTex", sweep.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(sweep.leftColor));
props.SetVector("_rightColor", _colorToVector4(sweep.rightColor));

return;
case ImageShader image:
pass = 4;
props.SetMatrix("_shaderMat", image.getShaderMat(ctm).toMatrix4x4());
props.SetMatrix("_shaderMat", image.getShaderMat(
_getShaderMatBase(layer.currentState, mesh.matrix)).toMatrix4x4());
props.SetTexture("_shaderTex", image.image.texture);
props.SetInt("_tileMode", (int) image.tileMode);
return;

}
public static PictureFlusher.RenderDraw convexFill(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw convexFill(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, 1.0f, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw fill0(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
public static PictureFlusher.CmdDraw fill0(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _fill0Mat.getMaterial(layer.ignoreClip);

return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw fill1(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw fill1(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, 1.0f, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh.boundsMesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw stroke0(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw stroke0(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
_getShaderPassAndProps(viewport, ctm, paint, alpha, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, alpha, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw stroke1(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
public static PictureFlusher.CmdDraw stroke1(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stroke1Mat;

return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw stencilClear(
public static PictureFlusher.CmdDraw stencilClear(
PictureFlusher.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;

props.SetVector("_viewport", viewport);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw stencil0(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
public static PictureFlusher.CmdDraw stencil0(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;

return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw stencil1(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
public static PictureFlusher.CmdDraw stencil1(PictureFlusher.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;

return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

public static PictureFlusher.RenderDraw tex(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw tex(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, 1.0f, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

}
public static PictureFlusher.RenderDraw texRT(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw texRT(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, 1.0f, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

}
public static PictureFlusher.RenderDraw texAlpha(PictureFlusher.RenderLayer layer, Paint paint,
public static PictureFlusher.CmdDraw texAlpha(PictureFlusher.RenderLayer layer, Paint paint,
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
return texAlpha(layer, paint, mesh, null, tex);
}
public static PictureFlusher.CmdDraw texAlpha(PictureFlusher.RenderLayer layer, Paint paint,
TextBlobMesh textMesh, Texture tex) {
return texAlpha(layer, paint, null, textMesh, tex);
}
public static PictureFlusher.CmdDraw texAlpha(PictureFlusher.RenderLayer layer, Paint paint,
MeshMesh mesh, TextBlobMesh textMesh, Texture tex) {
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
_getShaderPassAndProps(layer, paint, mesh, 1.0f, out var pass, out var props);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
textMesh = textMesh,
pass = pass,
material = mat,
properties = props,

public static PictureFlusher.RenderDraw maskFilter(PictureFlusher.RenderLayer layer, MeshMesh mesh,
public static PictureFlusher.CmdDraw maskFilter(PictureFlusher.RenderLayer layer, MeshMesh mesh,
PictureFlusher.RenderLayer renderLayer, float radius, Vector2 imgInc, float[] kernel) {
Vector4 viewport = layer.viewport;
var mat = _filterMat;

props.SetVector("_mf_imgInc", imgInc);
props.SetFloatArray("_mf_kernel", kernel);
return new PictureFlusher.RenderDraw {
return new PictureFlusher.CmdDraw {
mesh = mesh,
pass = pass,
material = mat,

33
Runtime/ui/painting/painting.cs


}
}
public abstract class ImageFilter {
public static ImageFilter blur(float sigmaX = 0.0f, float sigmaY = 0.0f) {
return new _BlurImageFilter(sigmaX, sigmaY);
}
public static ImageFilter matrix(Matrix3 transform, FilterMode filterMode = FilterMode.Point) {
return new _MatrixImageFilter(transform, filterMode);
}
}
class _BlurImageFilter : ImageFilter {
public _BlurImageFilter(float sigmaX, float sigmaY) {
this.sigmaX = sigmaX;
this.sigmaY = sigmaY;
}
public readonly float sigmaX;
public readonly float sigmaY;
}
class _MatrixImageFilter : ImageFilter {
public _MatrixImageFilter(Matrix3 transform, FilterMode filterMode) {
D.assert(transform != null);
this.transform = transform;
this.filterMode = filterMode;
}
public readonly Matrix3 transform;
public readonly FilterMode filterMode;
}
public class Paint {
static readonly Color _kColorDefault = new Color(0xFFFFFFFF);

public MaskFilter maskFilter = null;
public ImageFilter backdrop = null;
public PaintShader shader = null;
public bool invertColors = false;

this.filterMode = paint.filterMode;
this.colorFilter = paint.colorFilter;
this.maskFilter = paint.maskFilter;
this.backdrop = paint.backdrop;
this.shader = paint.shader;
this.invertColors = paint.invertColors;
}

230
Runtime/ui/painting/path.cs


public Rect getBounds() {
if (this._minX >= this._maxX || this._minY >= this._maxY) {
return null;
return Rect.zero;
}
return Rect.fromLTRB(this._minX, this._minY, this._maxX, this._maxY);

var cmd = (PathCommand) commands[i];
switch (cmd) {
case PathCommand.moveTo:
this._commandx = commands[i + 1];
this._commandy = commands[i + 2];
i += 3;
break;
this._expandBounds(this._commandx, this._commandy);
this._expandBounds(commands[i + 1], commands[i + 2]);
this._commandx = commands[i + 1];
this._commandy = commands[i + 2];

this._expandBounds(this._commandx, this._commandy);
this._expandBounds(commands[i + 1], commands[i + 2]);
this._expandBounds(commands[i + 3], commands[i + 4]);
this._expandBounds(commands[i + 5], commands[i + 6]);

this._cache = null;
}
public void relativeMoveTo(float x, float y) {
var x0 = this._commandx;
var y0 = this._commandy;
this._appendCommands(new[] {
(float) PathCommand.moveTo,
x + x0, y + y0,
});
}
}
}
public void lineTo(float x, float y) {
this._appendCommands(new[] {

D.assert(oval != null);
var center = oval.center;
this.addEllipse(center.dx, center.dy, oval.width / 2, oval.height / 2);
}
public void arcTo(float x1, float y1, float x2, float y2, float radius) {
var x0 = this._commandx;
var y0 = this._commandy;
// Calculate tangential circle to lines (x0,y0)-(x1,y1) and (x1,y1)-(x2,y2).
float dx0 = x0 - x1;
float dy0 = y0 - y1;
float dx1 = x2 - x1;
float dy1 = y2 - y1;
PathUtils.normalize(ref dx0, ref dy0);
PathUtils.normalize(ref dx1, ref dy1);
float a = Mathf.Acos(dx0 * dx1 + dy0 * dy1);
float d = radius / Mathf.Tan(a / 2.0f);
if (d > 10000.0f) {
this.lineTo(x1, y1);
return;
}
float cx, cy, a0, a1;
PathWinding dir;
float cross = dx1 * dy0 - dx0 * dy1;
if (cross > 0.0f) {
cx = x1 + dx0 * d + dy0 * radius;
cy = y1 + dy0 * d + -dx0 * radius;
a0 = Mathf.Atan2(dx0, -dy0);
a1 = Mathf.Atan2(-dx1, dy1);
dir = PathWinding.clockwise;
} else {
cx = x1 + dx0 * d + -dy0 * radius;
cy = y1 + dy0 * d + dx0 * radius;
a0 = Mathf.Atan2(-dx0, dy0);
a1 = Mathf.Atan2(dx1, -dy1);
dir = PathWinding.counterClockwise;
}
this.addArc(cx, cy, radius, a0, a1, dir);
}
public void addArc(Rect rect, float startAngle, float sweepAngle, bool forceMoveTo = true) {
var mat = Matrix3.makeScale(rect.width / 2, rect.height / 2);
var center = rect.center;
mat.postTranslate(center.dx, center.dy);
var vals = this._getArcCommands(0, 0, 1, startAngle, startAngle + sweepAngle,
sweepAngle >= 0 ? PathWinding.clockwise : PathWinding.counterClockwise, forceMoveTo);
this._transformCommands(vals, mat);
this._appendCommands(vals.ToArray());
}
public Path transform(Matrix3 mat) {
Path ret = new Path();
var i = 0;
while (i < this._commands.Count) {
var cmd = (PathCommand) this._commands[i];
switch (cmd) {
case PathCommand.moveTo:
var res_move = mat.mapXY(this._commands[i + 1], this._commands[i + 2]);
ret.moveTo(res_move.dx, res_move.dy);
i += 3;
break;
case PathCommand.lineTo:
var res_lineto = mat.mapXY(this._commands[i + 1], this._commands[i + 2]);
ret.lineTo(res_lineto.dx, res_lineto.dy);
i += 3;
break;
case PathCommand.bezierTo:
var res1 = mat.mapXY(this._commands[i + 1], this._commands[i + 2]);
var res2 = mat.mapXY(this._commands[i + 3], this._commands[i + 4]);
var res3 = mat.mapXY(this._commands[i + 5], this._commands[i + 6]);
ret.bezierTo(res1.dx, res1.dy, res2.dx, res2.dy, res3.dx, res3.dy);
i += 7;
break;
case PathCommand.close:
i++;
break;
case PathCommand.winding:
i += 2;
break;
default:
D.assert(false, "unknown cmd: " + cmd);
break;
}
}
return ret;
}
void _transformCommands(List<float> commands, Matrix3 mat) {
if (mat == null) {
return;
}
var i = 0;
while (i < commands.Count) {
var cmd = (PathCommand) commands[i];
switch (cmd) {
case PathCommand.moveTo:
case PathCommand.lineTo:
var res = mat.mapXY(commands[i + 1], commands[i + 2]);
commands[i + 1] = res.dx;
commands[i + 2] = res.dy;
i += 3;
break;
case PathCommand.bezierTo:
var res1 = mat.mapXY(commands[i + 1], commands[i + 2]);
commands[i + 1] = res1.dx;
commands[i + 2] = res1.dy;
var res2 = mat.mapXY(commands[i + 3], commands[i + 4]);
commands[i + 3] = res2.dx;
commands[i + 4] = res2.dy;
var res3 = mat.mapXY(commands[i + 5], commands[i + 6]);
commands[i + 5] = res3.dx;
commands[i + 6] = res3.dy;
i += 7;
break;
case PathCommand.close:
i++;
break;
case PathCommand.winding:
i += 2;
break;
default:
D.assert(false, "unknown cmd: " + cmd);
break;
}
}
}
List<float> _getArcCommands(float cx, float cy, float r, float a0, float a1, PathWinding dir, bool forceMoveTo) {
// Clamp angles
float da = a1 - a0;
if (dir == PathWinding.clockwise) {
if (Mathf.Abs(da) >= Mathf.PI * 2) {
da = Mathf.PI * 2;
} else {
while (da < 0.0f) {
da += Mathf.PI * 2;
}
if (da <= 1e-5) {
return new List<float>();
}
}
} else {
if (Mathf.Abs(da) >= Mathf.PI * 2) {
da = -Mathf.PI * 2;
} else {
while (da > 0.0f) {
da -= Mathf.PI * 2;
}
if (da >= -1e-5) {
return new List<float>();
}
}
}
// Split arc into max 90 degree segments.
int ndivs = Mathf.Max(1, Mathf.Min((int) (Mathf.Abs(da) / (Mathf.PI * 0.5f) + 0.5f), 5));
float hda = (da / ndivs) / 2.0f;
float kappa = Mathf.Abs(4.0f / 3.0f * (1.0f - Mathf.Cos(hda)) / Mathf.Sin(hda));
if (dir == PathWinding.counterClockwise) {
kappa = -kappa;
}
PathCommand move = (forceMoveTo || this._commands.Count == 0) ? PathCommand.moveTo : PathCommand.lineTo;
float px = 0, py = 0, ptanx = 0, ptany = 0;
List<float> vals = new List<float>();
for (int i = 0; i <= ndivs; i++) {
float a = a0 + da * (i / (float) ndivs);
float dx = Mathf.Cos(a);
float dy = Mathf.Sin(a);
float x = cx + dx * r;
float y = cy + dy * r;
float tanx = -dy * r * kappa;
float tany = dx * r * kappa;
if (i == 0) {
vals.Add((float) move);
vals.Add(x);
vals.Add(y);
} else {
vals.Add((float) PathCommand.bezierTo);
vals.Add(px + ptanx);
vals.Add(py + ptany);
vals.Add(x - tanx);
vals.Add(y - tany);
vals.Add(x);
vals.Add(y);
}
px = x;
py = y;
ptanx = tanx;
ptany = tany;
}
return vals;
}
public void addArc(float cx, float cy, float r, float a0, float a1, PathWinding dir, bool forceMoveTo = true) {
var vals = this._getArcCommands(cx, cy, r, a0, a1, dir, forceMoveTo);
this._appendCommands(vals.ToArray());
}
public void addPolygon(IList<Offset> points, bool close) {

void _addPoint(PathPoint point) {
if (this._paths.Count == 0) {
this.addPath();
this.addPoint(0, 0, PointFlags.corner);
}
var path = this._paths.Last();

}
var points = TessellationGenerator.tessellateBezier(x1, y1, x2, y2, x3, y3, x4, y4, this._tessTol);
D.assert(points.Count > 0);
points[points.Count - 1].flags = flags;
foreach (var point in points) {
this._addPoint(point);

20
Runtime/ui/painting/shader.cs


get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
public Matrix3 getGradientMat(Matrix3 mat) {
if (this.matrix != null) {
mat.postConcat(this.matrix);
}

get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
public Matrix3 getGradientMat(Matrix3 mat) {
if (this.matrix != null) {
mat.postConcat(this.matrix);
}

get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
public Matrix3 getGradientMat(Matrix3 mat) {
if (this.matrix != null) {
mat.postConcat(this.matrix);
}

public readonly TileMode tileMode;
public readonly Matrix3 matrix;
public Matrix3 getShaderMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
public Matrix3 getShaderMat(Matrix3 mat) {
if (this.matrix != null) {
mat.postConcat(this.matrix);
}

2
Runtime/ui/painting/tessellation_generator.cs


}
public void touch(long timeTolive = 5) {
this._timeToLive = timeTolive + MeshGenerator.frameCount;
this._timeToLive = timeTolive + TextBlobMesh.frameCount;
}
}

171
Runtime/ui/painting/txt/font_manager.cs


using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using UnityEngine;

}
}
class FontRef : IEquatable<FontRef> {
public readonly string familyName;
public readonly FontWeight fontWeight;
public readonly FontStyle fontStyle;
public FontRef(string familyName, FontWeight fontWeight, FontStyle fontStyle) {
this.familyName = familyName;
this.fontWeight = fontWeight;
this.fontStyle = fontStyle;
}
public bool Equals(FontRef other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return string.Equals(this.familyName, other.familyName) && this.fontWeight == other.fontWeight && this.fontStyle == other.fontStyle;
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((FontRef) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = (this.familyName != null ? this.familyName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.fontWeight != null ? this.fontWeight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) this.fontStyle;
return hashCode;
}
}
public static bool operator ==(FontRef left, FontRef right) {
return Equals(left, right);
}
public static bool operator !=(FontRef left, FontRef right) {
return !Equals(left, right);
}
public override string ToString() {
return $"{nameof(this.familyName)}: {this.familyName}, {nameof(this.fontWeight)}: {this.fontWeight}, {nameof(this.fontStyle)}: {this.fontStyle}";
}
}
readonly Dictionary<string, FontInfo> _fonts = new Dictionary<string, FontInfo>();
readonly Dictionary<FontRef, FontInfo> _fonts = new Dictionary<FontRef, FontInfo>();
static readonly int defaultFontSize = 14;

Font.textureRebuilt += this.onFontTextureRebuilt;
}
public void addFont(Font font) {
public void addFont(Font font, string familyName,
FontWeight fontWeight = null, FontStyle fontStyle = FontStyle.normal) {
if (fontWeight == null) {
fontWeight = FontWeight.normal;
}
FontRef fontRef = new FontRef(familyName, fontWeight, fontStyle);
D.assert(font.dynamic, $"adding font which is not dynamic is not allowed {font.name}");
FontInfo current;
this._fonts.TryGetValue(fontRef, out current);
D.assert(current == null || current.font == font, $"font with key {fontRef} already exists");
foreach (var fontName in font.fontNames) {
this._fonts[fontName] = fontInfo;
}
this._fonts[fontRef] = fontInfo;
internal FontInfo getOrCreate(string name) {
if (this._fonts.TryGetValue(name, out var fontInfo)) {
internal FontInfo getOrCreate(string familyName, FontWeight fontWeight, FontStyle fontStyle) {
if (fontWeight == null) {
fontWeight = FontWeight.normal;
}
FontRef fontRef = new FontRef(familyName, fontWeight, fontStyle);
if (this._fonts.TryGetValue(fontRef, out var fontInfo)) {
var osFont = Font.CreateDynamicFontFromOSFont(name, defaultFontSize);
// fallback to normal weight & style
if (fontWeight != FontWeight.normal || fontStyle != FontStyle.normal) {
fontInfo = this.getOrCreate(familyName, FontWeight.normal, FontStyle.normal);
if (fontInfo != null) {
return fontInfo;
}
}
var osFont = Font.CreateDynamicFontFromOSFont(familyName, defaultFontSize);
foreach (var fontName in osFont.fontNames) {
this._fonts[fontName] = newFont;
}
fontRef = new FontRef(familyName, fontWeight, fontStyle);
this._fonts[fontRef] = newFont;
return newFont;
}

if (entry != null) {
entry.onTextureRebuilt();
}
}
}
class GlyphInfo {
public static GlyphInfo empty = new GlyphInfo(Rect.zero,0, 0, new Vector2(0, 0),
new Vector2(0, 0), new Vector2(0, 0), new Vector2(0, 0));
public readonly Rect rect;
public readonly float advance;
public readonly float glyphHeight;
public readonly Vector2 uvTopLeft;
public readonly Vector2 uvTopRight;
public readonly Vector2 uvBottomLeft;
public readonly Vector2 uvBottomRight;
public GlyphInfo(CharacterInfo info) {
this.rect = Rect.fromLTRB(info.minX, -info.maxY, info.maxX, -info.minY);
this.advance = info.advance;
this.glyphHeight = info.glyphHeight;
this.uvTopLeft = info.uvTopLeft;
this.uvTopRight = info.uvTopRight;
this.uvBottomLeft = info.uvBottomLeft;
this.uvBottomRight = info.uvBottomRight;
}
public GlyphInfo(Rect rect, float advance, float glyphHeight,
Vector2 uvTopLeft, Vector2 uvTopRight, Vector2 uvBottomLeft, Vector2 uvBottomRight) {
this.rect = rect;
this.advance = advance;
this.glyphHeight = glyphHeight;
this.uvTopLeft = uvTopLeft;
this.uvTopRight = uvTopRight;
this.uvBottomLeft = uvBottomLeft;
this.uvBottomRight = uvBottomRight;
}
}
public static class FontExtension
{
internal static GlyphInfo getGlyphInfo(this Font font, char ch, int fontSize, UnityEngine.FontStyle fontStyle) {
if (fontSize <= 0) {
return GlyphInfo.empty;
}
CharacterInfo info;
bool success = font.GetCharacterInfo(ch, out info, fontSize, fontStyle);
if (!success) {
if (!char.IsControl(ch)) {
Debug.LogWarning($"character info not found from the given font: character '{ch}' (code{(int)ch}) font: ${font.name}");
}
return GlyphInfo.empty;
}
return new GlyphInfo(info);
}
internal static void RequestCharactersInTextureSafe(this Font font, string text, int fontSize,
UnityEngine.FontStyle fontStyle = UnityEngine.FontStyle.Normal) {
if (fontSize <= 0) {
return;
}
font.RequestCharactersInTexture(text, fontSize, fontStyle);
}
}
}

83
Runtime/ui/painting/txt/mesh_generator.cs


}
public void touch(long timeTolive = 5) {
this._timeToLive = timeTolive + MeshGenerator.frameCount;
this._timeToLive = timeTolive + TextBlobMesh.frameCount;
static class MeshGenerator {
class TextBlobMesh {
readonly TextBlob _textBlob;
readonly float _scale;
readonly Matrix3 _transform;
MeshMesh _mesh;
bool _resolved;
public TextBlobMesh(TextBlob textBlob, float scale, Matrix3 transform) {
this._textBlob = textBlob;
this._scale = scale;
this._transform = transform;
}
public static long frameCount {
get { return _frameCount; }
}

}
}
public static MeshMesh generateMesh(TextBlob textBlob, float scale) {
var style = textBlob.style;
var fontInfo = FontManager.instance.getOrCreate(style.fontFamily);
var key = new MeshKey(textBlob.instanceId, scale);
public MeshMesh resovleMesh() {
if (this._resolved) {
return this._mesh;
}
this._resolved = true;
var style = this._textBlob.style;
var fontInfo = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle);
var key = new MeshKey(this._textBlob.instanceId, this._scale);
return meshInfo.mesh;
this._mesh = meshInfo.mesh.transform(this._transform);
return this._mesh;
var length = textBlob.textSize;
var text = textBlob.text;
var fontSizeToLoad = Mathf.CeilToInt(style.UnityFontSize * scale);
var subText = textBlob.text.Substring(textBlob.textOffset, textBlob.textSize);
font.RequestCharactersInTexture(subText, fontSizeToLoad, style.UnityFontStyle);
var length = this._textBlob.textSize;
var text = this._textBlob.text;
var fontSizeToLoad = Mathf.CeilToInt(style.UnityFontSize * this._scale);
var ch = text[charIndex + textBlob.textOffset];
var ch = text[charIndex + this._textBlob.textOffset];
var position = textBlob.positions[charIndex];
var position = this._textBlob.positions[charIndex];
CharacterInfo charInfo;
font.GetCharacterInfo(ch, out charInfo, fontSizeToLoad, style.UnityFontStyle);
var minX = charInfo.minX / scale;
var maxX = charInfo.maxX / scale;
var minY = charInfo.minY / scale;
var maxY = charInfo.maxY / scale;
if (fontSizeToLoad == 0) {
continue;
}
var glyphInfo = font.getGlyphInfo(ch, fontSizeToLoad, style.UnityFontStyle);
var minX = glyphInfo.rect.left / this._scale;
var maxX = glyphInfo.rect.right / this._scale;
var minY = glyphInfo.rect.top / this._scale;
var maxY = glyphInfo.rect.bottom / this._scale;
vertices.Add(new Vector3((position.x + minX), (position.y - maxY), 0));
vertices.Add(new Vector3((position.x + maxX), (position.y - maxY), 0));
vertices.Add(new Vector3((position.x + maxX), (position.y - minY), 0));
vertices.Add(new Vector3((position.x + minX), (position.y - minY), 0));
vertices.Add(new Vector3((position.x + minX), (position.y + minY), 0));
vertices.Add(new Vector3((position.x + maxX), (position.y + minY), 0));
vertices.Add(new Vector3((position.x + maxX), (position.y + maxY), 0));
vertices.Add(new Vector3((position.x + minX), (position.y + maxY), 0));
triangles.Add(baseIndex);
triangles.Add(baseIndex + 1);

triangles.Add(baseIndex + 3);
uv.Add(charInfo.uvTopLeft);
uv.Add(charInfo.uvTopRight);
uv.Add(charInfo.uvBottomRight);
uv.Add(charInfo.uvBottomLeft);
uv.Add(glyphInfo.uvTopLeft);
uv.Add(glyphInfo.uvTopRight);
uv.Add(glyphInfo.uvBottomRight);
uv.Add(glyphInfo.uvBottomLeft);
this._mesh = null;
return null;
}

return mesh;
this._mesh = mesh.transform(this._transform);
return this._mesh;
}
}
}

23
Runtime/ui/painting/txt/text_blob.cs


namespace Unity.UIWidgets.ui {
public class TextBlob {
public TextBlob(string text, int textOffset, int textSize, Vector2d[] positions, Rect bounds, TextStyle style) {
internal TextBlob(string text, int textOffset, int textSize, Vector2d[] positions, Rect bounds, TextStyle style) {
this.instanceId = ++_nextInstanceId;
this.positions = positions;
this.text = text;

}
static long _nextInstanceId = 0;
public readonly long instanceId;
public readonly string text;
public readonly int textOffset;
public readonly int textSize;
public readonly Vector2d[] positions;
public readonly TextStyle style;
public readonly Rect bounds; // bounds with positions[start] as origin
internal readonly long instanceId;
internal readonly string text;
internal readonly int textOffset;
internal readonly int textSize;
internal readonly Vector2d[] positions;
internal readonly TextStyle style;
internal readonly Rect bounds; // bounds with positions[start] as origin
}
public class TextBlobBuilder {

int _size;
Rect _bounds;
public void allocRunPos(TextStyle style, string text, int offset, int size) {
public void allocRunPos(painting.TextStyle style, string text, int offset, int size, float textScaleFactor = 1.0f) {
this.allocRunPos(TextStyle.applyStyle(null, style, textScaleFactor), text, offset, size);
}
internal void allocRunPos(TextStyle style, string text, int offset, int size) {
this._style = style;
this._text = text;
this._textOffset = offset;

148
Runtime/ui/text.cs


using System;
using System.Collections.Generic;
namespace Unity.UIWidgets.ui {
public enum FontStyle {

}
}
public class TextStyle : IEquatable<TextStyle> {
internal class TextStyle : IEquatable<TextStyle> {
public readonly Color color = Color.fromARGB(255, 0, 0, 0);
public readonly float fontSize = 14.0f;
public readonly FontWeight fontWeight = FontWeight.w400;

internal UnityEngine.FontStyle UnityFontStyle {
get {
bool isBold = this.fontWeight == FontWeight.bold;
if (this.fontWeight == FontWeight.w700) {
if (isBold) {
return UnityEngine.FontStyle.BoldAndItalic;
}
else {

else if (this.fontWeight == FontWeight.w700) {
else if (isBold) {
return UnityEngine.FontStyle.Bold;
}

get { return (int) this.fontSize; }
}
public static TextStyle applyStyle(TextStyle currentStyle, painting.TextStyle style, float textScaleFactor) {
if (currentStyle != null) {
return new ui.TextStyle(
color: style.color ?? currentStyle.color,
fontSize: style.fontSize != null ? style.fontSize * textScaleFactor : currentStyle.fontSize,
fontWeight: style.fontWeight ?? currentStyle.fontWeight,
fontStyle: style.fontStyle ?? currentStyle.fontStyle,
letterSpacing: style.letterSpacing ?? currentStyle.letterSpacing,
wordSpacing: style.wordSpacing ?? currentStyle.wordSpacing,
textBaseline: style.textBaseline ?? currentStyle.textBaseline,
height: style.height ?? currentStyle.height,
decoration: style.decoration ?? currentStyle.decoration,
decorationColor: style.decorationColor ?? currentStyle.decorationColor,
fontFamily: style.fontFamily ?? currentStyle.fontFamily,
background: style.background ?? currentStyle.background
);
}
return new ui.TextStyle(
color: style.color,
fontSize: style.fontSize * textScaleFactor,
fontWeight: style.fontWeight,
fontStyle: style.fontStyle,
letterSpacing: style.letterSpacing,
wordSpacing: style.wordSpacing,
textBaseline: style.textBaseline,
height: style.height,
decoration: style.decoration,
decorationColor: style.decorationColor,
fontFamily: style.fontFamily,
background: style.background
);
}
public bool Equals(TextStyle other) {
if (ReferenceEquals(null, other)) {
return false;

unchecked {
var hashCode = (this.color != null ? this.color.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontSize.GetHashCode();
hashCode = (hashCode * 397) ^ this.fontWeight.GetHashCode();
hashCode = (hashCode * 397) ^ (this.fontWeight != null ? this.fontWeight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontStyle.GetHashCode();
hashCode = (hashCode * 397) ^ this.letterSpacing.GetHashCode();
hashCode = (hashCode * 397) ^ this.wordSpacing.GetHashCode();

public TextStyle(Color color = null, float? fontSize = null,
FontWeight? fontWeight = null, FontStyle? fontStyle = null, float? letterSpacing = null,
FontWeight fontWeight = null, FontStyle? fontStyle = null, float? letterSpacing = null,
float? wordSpacing = null, TextBaseline? textBaseline = null, float? height = null,
TextDecoration decoration = null, TextDecorationStyle? decorationStyle = null, Color decorationColor = null,
string fontFamily = null,

public class ParagraphStyle : IEquatable<ParagraphStyle> {
public ParagraphStyle(TextAlign? textAlign = null,
TextDirection? textDirection = null,
FontWeight? fontWeight = null,
FontWeight fontWeight = null,
FontStyle? fontStyle = null,
int? maxLines = null,
float? fontSize = null,

unchecked {
var hashCode = this.textAlign.GetHashCode();
hashCode = (hashCode * 397) ^ this.textDirection.GetHashCode();
hashCode = (hashCode * 397) ^ this.fontWeight.GetHashCode();
hashCode = (hashCode * 397) ^ (this.fontWeight != null ? this.fontWeight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontStyle.GetHashCode();
hashCode = (hashCode * 397) ^ this.maxLines.GetHashCode();
hashCode = (hashCode * 397) ^ this.fontSize.GetHashCode();

}
}
public TextStyle getTextStyle() {
internal TextStyle getTextStyle() {
return new TextStyle(
fontWeight: this.fontWeight,
fontStyle: this.fontStyle,

public readonly TextAlign? textAlign;
public readonly TextDirection? textDirection;
public readonly FontWeight? fontWeight;
public readonly FontWeight fontWeight;
public readonly FontStyle? fontStyle;
public readonly int? maxLines;
public readonly float? fontSize;

downstream,
}
public enum FontWeight {
w400, // normal
w700, // bold
public class FontWeight: IEquatable<FontWeight> {
private FontWeight(int index) {
this.index = index;
}
public readonly int index;
public static readonly FontWeight w100 = new FontWeight(0);
public static readonly FontWeight w200 = new FontWeight(1);
public static readonly FontWeight w300 = new FontWeight(2);
public static readonly FontWeight w400 = new FontWeight(3);
public static readonly FontWeight w500 = new FontWeight(4);
public static readonly FontWeight w600 = new FontWeight(5);
public static readonly FontWeight w700 = new FontWeight(6);
public static readonly FontWeight w800 = new FontWeight(7);
public static readonly FontWeight w900 = new FontWeight(8);
public static readonly FontWeight normal = w400;
public static readonly FontWeight bold = w700;
public static readonly List<FontWeight> values = new List<FontWeight>{
w100, w200, w300, w400, w500, w600, w700, w800, w900
};
public static readonly Dictionary<int, int> indexToFontWeight = new Dictionary<int, int> {
{0, 100},
{1, 200},
{2, 300},
{3, 400},
{4, 500},
{5, 600},
{6, 700},
{7, 800},
{8, 900},
};
public bool Equals(FontWeight other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.index == other.index;
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((FontWeight) obj);
}
public override int GetHashCode() {
return this.index;
}
public static bool operator ==(FontWeight left, FontWeight right) {
return Equals(left, right);
}
public static bool operator !=(FontWeight left, FontWeight right) {
return !Equals(left, right);
}
public override string ToString() {
return $"FontWeight.w{this.weightValue}";
}
public int weightValue {
get {
return indexToFontWeight[this.index];
}
}
public class TextPosition : IEquatable<TextPosition> {
public readonly int offset;

15
Runtime/ui/txt/layout.cs


using UnityEngine;
namespace Unity.UIWidgets.ui {
public class Layout {
class Layout {
int _start;
int _count;
List<float> _advances = new List<float>();

this._advances.Clear();
this._positions.Clear();
this._count = count;
var font = FontManager.instance.getOrCreate(style.fontFamily).font;
font.RequestCharactersInTexture(this._text.Substring(start, count),
var font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font;
font.RequestCharactersInTextureSafe(this._text.Substring(start, count),
style.UnityFontSize,
style.UnityFontStyle);

int charIndex = start + i;
var ch = text[charIndex];
CharacterInfo characterInfo;
font.GetCharacterInfo(ch, out characterInfo, style.UnityFontSize, style.UnityFontStyle);
var glyphInfo = font.getGlyphInfo(ch, style.UnityFontSize, style.UnityFontStyle);
var rect = Rect.fromLTRB(characterInfo.minX, -characterInfo.maxY, characterInfo.maxX,
-characterInfo.minY);
var rect = glyphInfo.rect;
rect = rect.translate(this._advance, 0);
if (this._bounds == null || this._bounds.isEmpty) {
this._bounds = rect;

}
this._positions.Add(this._advance);
float advance = characterInfo.advance;
float advance = glyphInfo.advance;
if (ch == '\t') {
advance = this._tabStops.nextTab((this._advance + offset)) - this._advance;
}

33
Runtime/ui/txt/linebreaker.cs


using UnityEngine;
namespace Unity.UIWidgets.ui {
public class TabStops {
class TabStops {
int _tabWidth = int.MaxValue;
Font _font;

}
if (this._tabWidth == int.MaxValue) {
this._font.RequestCharactersInTexture(" ", this._fontSize);
CharacterInfo characterInfo;
this._font.GetCharacterInfo(' ', out characterInfo, this._fontSize);
this._tabWidth = characterInfo.advance * kTabSpaceCount;
this._font.RequestCharactersInTextureSafe(" ", this._fontSize);
if (this._fontSize > 0) {
var glyphInfo = this._font.getGlyphInfo(' ', this._fontSize, UnityEngine.FontStyle.Normal);
this._tabWidth = (int)Math.Round(glyphInfo.advance * kTabSpaceCount);
}
}
if (this._tabWidth == 0) {

}
}
public class Candidate {
class Candidate {
public int offset;
public int pre;
public float preBreak;

public int postSpaceCount;
}
public class LineBreaker {
class LineBreaker {
const float ScoreInfty = float.MaxValue;
const float ScoreDesperate = 1e10f;

this._charWidths, start, this._tabStops);
}
var font = FontManager.instance.getOrCreate(style.fontFamily).font;
int current = this._wordBreaker.current();
int afterWord = start;
int lastBreak = start;

int candIndex = this._candidates.Count;
this._candidates.Add(cand);
if (cand.postBreak - this._preBreak > this._lineWidth) {
if (this._bestBreak == this._lastBreak) {
this._bestBreak = candIndex;
}
this._pushGreedyBreak();
}
while (this._lastBreak != candIndex && cand.postBreak - this._preBreak > this._lineWidth) {
for (int i = this._lastBreak + 1; i < candIndex; i++) {
float penalty = this._candidates[i].penalty;
if (penalty <= this._bestScore) {
this._bestBreak = i;
this._bestScore = penalty;
}
}
if (this._bestBreak == this._lastBreak) {
this._bestBreak = candIndex;
}
this._pushGreedyBreak();
}

2
Runtime/ui/txt/paint_record.cs


namespace Unity.UIWidgets.ui {
public class PaintRecord {
class PaintRecord {
public PaintRecord(TextStyle style, Offset offset, TextBlob _text,
FontMetrics metrics,
int line, float runWidth) {

96
Runtime/ui/txt/paragraph.cs


}
}
public class CodeUnitRun {
class CodeUnitRun {
public readonly int lineNumber;
public readonly TextDirection direction;
public readonly Range<int> codeUnits;

}
public class FontMetrics {
class FontMetrics {
public readonly float ascent;
public readonly float leading = 0.0f;
public readonly float descent;

public static FontMetrics fromFont(Font font, int fontSize) {
var ascent = -font.ascent * fontSize / font.fontSize;
var descent = (font.lineHeight - font.ascent) * fontSize / font.fontSize;
float? fxHeight = null;
font.RequestCharactersInTexture("x", fontSize);
CharacterInfo charInfo;
if (font.GetCharacterInfo('x', out charInfo, fontSize)) {
fxHeight = charInfo.glyphHeight;
}
font.RequestCharactersInTextureSafe("x", fontSize, UnityEngine.FontStyle.Normal);
var glyphInfo = font.getGlyphInfo('x', fontSize, UnityEngine.FontStyle.Normal);
float fxHeight = glyphInfo.glyphHeight;
public class LineStyleRun {
class LineStyleRun {
public readonly int start;
public readonly int end;
public readonly TextStyle style;

}
}
public class PositionWithAffinity {
class PositionWithAffinity {
public readonly int position;
public readonly TextAffinity affinity;

}
}
public class GlyphPosition {
class GlyphPosition {
public readonly Range<float> xPos;
public readonly Range<int> codeUnits;

}
}
public class Range<T> : IEquatable<Range<T>> {
class Range<T> : IEquatable<Range<T>> {
public Range(T start, T end) {
this.start = start;
this.end = end;

public readonly T start, end;
}
public static class RangeUtils {
static class RangeUtils {
public static Range<float> shift(Range<float> value, float shift) {
return new Range<float>(value.start + shift, value.end + shift);
}

public class GlyphLine {
class GlyphLine {
public readonly List<GlyphPosition> positions;
public readonly int totalCountUnits;

}
public void paint(Canvas canvas, Offset offset) {
foreach (var paintRecord in this._paintRecords) {
this.paintBackground(canvas, paintRecord, offset);
}
foreach (var paintRecord in this._paintRecords) {
var paint = new Paint {
filterMode = FilterMode.Bilinear,

}
var textStyle = this._paragraphStyle.getTextStyle();
this._tabStops.setFont(FontManager.instance.getOrCreate(textStyle.fontFamily).font,
this._tabStops.setFont(FontManager.instance.getOrCreate(textStyle.fontFamily,
textStyle.fontWeight, textStyle.fontStyle).font,
textStyle.UnityFontSize);
this._needsLayout = false;

List<PaintRecord> paintRecords = new List<PaintRecord>();
for (int i = 0; i < lineRuns.Count; ++i) {
var run = lineRuns[i];
string text = this._text;
layout.doLayout(runXOffset, this._text, textStart, textCount, run.style);
string ellipsis = this._paragraphStyle.ellipsis;
if (!string.IsNullOrEmpty(ellipsis) && !this._width.isInfinite() && !lineRange.hardBreak
&& i == lineRuns.Count - 1 && (lineNumber == lineLimit - 1 || this._paragraphStyle.maxLines == null)) {
float ellipsisWidth = Layout.measureText(runXOffset, ellipsis, 0,
ellipsis.Length, run.style, null, 0, this._tabStops);
List<float> textAdvances = new List<float>(textCount);
for (int index = 0; index < textCount;++index) {
textAdvances.Add(0);
}
float textWidth = Layout.measureText(runXOffset, this._text, textStart, textCount,
run.style, textAdvances, 0, this._tabStops);
int truncateCount = 0;
while (truncateCount < textCount &&
runXOffset + textWidth + ellipsisWidth > this._width) {
textWidth -= textAdvances[textCount - truncateCount - 1];
truncateCount++;
}
var ellipsizedText = this._text.Substring(textStart, textCount - truncateCount) + ellipsis;
textStart = 0;
textCount = ellipsizedText.Length;
text = ellipsizedText;
if (this._paragraphStyle.maxLines == null) {
lineLimit = lineNumber + 1;
this._didExceedMaxLines = true;
}
}
layout.doLayout(runXOffset, text, textStart, textCount, run.style);
if (layout.nGlyphs() == 0) {
continue;
}

builder.allocRunPos(run.style, this._text, textStart, textCount);
builder.allocRunPos(run.style, text, textStart, textCount);
builder.setBounds(layout.getBounds());
glyphPositions.Clear();

continue;
}
var font = FontManager.instance.getOrCreate(run.style.fontFamily).font;
var font = FontManager.instance.getOrCreate(run.style.fontFamily,
run.style.fontWeight, run.style.fontStyle).font;
var metrics = FontMetrics.fromFont(font, run.style.UnityFontSize);
paintRecords.Add(new PaintRecord(run.style, new Offset(runXOffset, 0),
builder.make(), metrics, lineNumber, layout.getAdvance()

if (paintRecords.Count == 0) {
var defaultStyle = this._paragraphStyle.getTextStyle();
var defaultFont = FontManager.instance.getOrCreate(defaultStyle.fontFamily).font;
var defaultFont = FontManager.instance.getOrCreate(defaultStyle.fontFamily,
defaultStyle.fontWeight, defaultStyle.fontStyle).font;
var metrics = FontMetrics.fromFont(defaultFont, defaultStyle.UnityFontSize);
updateLineMetrics(metrics, defaultStyle);
}

}
public void setText(string text, StyledRuns runs) {
internal void setText(string text, StyledRuns runs) {
this._text = text;
this._runs = runs;
this._needsLayout = true;

return TextBox.fromLTBD(0, top, 0, bottom, TextDirection.ltr);
}
public PositionWithAffinity getGlyphPositionAtCoordinate(float dx, float dy) {
internal PositionWithAffinity getGlyphPositionAtCoordinate(float dx, float dy) {
if (this._lineHeights.Count == 0) {
return new PositionWithAffinity(0, TextAffinity.downstream);
}

return Mathf.Max(lineCount - 1, 0);
}
public LineRange getLineRange(int lineIndex) {
internal LineRange getLineRange(int lineIndex) {
public Range<int> getWordBoundary(int offset) {
internal Range<int> getWordBoundary(int offset) {
WordSeparate s = new WordSeparate(this._text);
return s.findWordRange(offset);
}

}
}
void paintBackground(Canvas canvas, PaintRecord record, Offset baseOffset) {
if (record.style.background == null) {
return;
}
var metrics = record.metrics;
Rect rect = Rect.fromLTRB(0, metrics.ascent, record.runWidth, metrics.descent);
rect = rect.shift(baseOffset + record.offset);
canvas.drawRect(rect, record.style.background);
}
float getLineXOffset(float lineTotalAdvance) {
if (this._width.isInfinite()) {
return 0;

}
}
public class SplayTree<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey> {
class SplayTree<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey> {
SplayTreeNode root;
int count;
int version = 0;

12
Runtime/ui/txt/paragraph_builder.cs


List<int> _styleStack = new List<int>();
int _paragraph_style_index;
public interface ITextStyleProvider {
TextStyle getTextStyle(TextStyle current = null);
}
public ParagraphBuilder(ParagraphStyle style) {
this.setParagraphStyle(style);
}

return paragraph;
}
public void pushStyle(ITextStyleProvider style) {
var newStyle = style.getTextStyle(this.peekStyle());
public void pushStyle(painting.TextStyle style, float textScaleFactor) {
var newStyle = TextStyle.applyStyle(this.peekStyle(), style, textScaleFactor: textScaleFactor);
public void pushStyle(TextStyle style) {
internal void pushStyle(TextStyle style) {
var styleIndex = this._runs.addStyle(style);
this._styleStack.Add(styleIndex);
this._runs.startRun(styleIndex, this._text.Length);

this._text.Append(text);
}
public TextStyle peekStyle() {
internal TextStyle peekStyle() {
return this._runs.getStyle(this.peekStyleIndex());
}

6
Runtime/ui/txt/styled_runs.cs


using System.Collections.Generic;
namespace Unity.UIWidgets.ui {
public class StyledRuns {
class StyledRuns {
readonly List<TextStyle> styles = new List<TextStyle>();
readonly List<IndexedRun> runs = new List<IndexedRun>();

}
}
public class Run {
internal class Run {
public readonly TextStyle style;
public readonly int start;
public readonly int end;

}
}
public class IndexedRun {
internal class IndexedRun {
public readonly int styleIndex = 0;
public readonly int start;
public int end;

16
Runtime/ui/txt/word_separate.cs


namespace Unity.UIWidgets.ui {
public class WordSeparate {
class WordSeparate {
enum characterType {
internal enum characterType {
LetterLike,
Symbol,
WhiteSpace

return new Range<int>(0, 0);
}
var t = this.classifyChar(index);
var t = classifyChar(this._text, index);
if (this.classifyChar(i) != t) {
if (classifyChar(this._text, i) != t) {
break;
}

int end = index;
for (int i = index; i < this._text.Length; ++i) {
if (!char.IsLowSurrogate(this._text[i])) {
if (this.classifyChar(i) != t) {
if (classifyChar(this._text, i) != t) {
break;
}

}
characterType classifyChar(int index) {
if (char.IsWhiteSpace(this._text, index)) {
internal static characterType classifyChar(string text, int index) {
if (char.IsWhiteSpace(text, index)) {
if (char.IsLetterOrDigit(this._text, index) || this._text[index] == '\'') {
if (char.IsLetterOrDigit(text, index) || text[index] == '\'') {
return characterType.LetterLike;
}

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存