committed by
GitHub
37 changed files with 1329 additions and 384 deletions
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -1 +1 @@ |
|||
Subproject commit 4464343aef5c8ab7a42fcb20a483a6058199f8b8 |
|||
Subproject commit aef10ae67dc55c95f49b52a505a0be33bfa297a5 |
|||
@ -1,3 +1,11 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
|
|||
<ItemGroup> |
|||
<AvailableItemName Include="AvaloniaXaml" /> |
|||
<AvailableItemName Include="AvaloniaResource" /> |
|||
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)AvaloniaItemSchema.xaml" /> |
|||
</ItemGroup> |
|||
<ItemGroup Condition="'$(EnableDefaultItems)'=='True'"> |
|||
<AvaloniaXaml Include="**\*.axaml" SubType="Designer" /> |
|||
<AvaloniaXaml Include="**\*.paml" SubType="Designer" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,18 @@ |
|||
<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties"> |
|||
<ContentType |
|||
Name="AvaloniaXaml" |
|||
DisplayName="Avalonia XAML" |
|||
ItemType="AvaloniaXaml"> |
|||
<NameValuePair Name="DependentFileExtensions" Value=".cs" /> |
|||
<NameValuePair Name="DefaultMetadata_SubType" Value="Designer" /> |
|||
</ContentType> |
|||
|
|||
<ItemType Name="AvaloniaXaml" DisplayName="Avalonia XAML" /> |
|||
<FileExtension Name=".axaml" ContentType="AvaloniaXaml" /> |
|||
<FileExtension Name=".paml" ContentType="AvaloniaXaml" /> |
|||
<ContentType |
|||
Name="AvaloniaResource" |
|||
DisplayName="Avalonia Resource" |
|||
ItemType="AvaloniaResource" |
|||
/> |
|||
</ProjectSchemaDefinitions> |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Layout |
|||
{ |
|||
/// <summary>
|
|||
/// Provides data for the <see cref="Layoutable.EffectiveViewportChanged"/> event.
|
|||
/// </summary>
|
|||
public class EffectiveViewportChangedEventArgs : EventArgs |
|||
{ |
|||
public EffectiveViewportChangedEventArgs(Rect effectiveViewport) |
|||
{ |
|||
EffectiveViewport = effectiveViewport; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="Rect"/> representing the effective viewport.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The viewport is expressed in coordinates relative to the control that the event is
|
|||
/// raised on.
|
|||
/// </remarks>
|
|||
public Rect EffectiveViewport { get; } |
|||
} |
|||
} |
|||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,178 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Media.TextFormatting.Unicode |
|||
{ |
|||
internal static class PropertyValueAliasHelper |
|||
{ |
|||
private static readonly Dictionary<Script, string> s_scriptToTag = |
|||
new Dictionary<Script, string>{ |
|||
{ Script.Unknown, "Zzzz"}, |
|||
{ Script.Common, "Zyyy"}, |
|||
{ Script.Inherited, "Zinh"}, |
|||
{ Script.Adlam, "Adlm"}, |
|||
{ Script.CaucasianAlbanian, "Aghb"}, |
|||
{ Script.Ahom, "Ahom"}, |
|||
{ Script.Arabic, "Arab"}, |
|||
{ Script.ImperialAramaic, "Armi"}, |
|||
{ Script.Armenian, "Armn"}, |
|||
{ Script.Avestan, "Avst"}, |
|||
{ Script.Balinese, "Bali"}, |
|||
{ Script.Bamum, "Bamu"}, |
|||
{ Script.BassaVah, "Bass"}, |
|||
{ Script.Batak, "Batk"}, |
|||
{ Script.Bengali, "Beng"}, |
|||
{ Script.Bhaiksuki, "Bhks"}, |
|||
{ Script.Bopomofo, "Bopo"}, |
|||
{ Script.Brahmi, "Brah"}, |
|||
{ Script.Braille, "Brai"}, |
|||
{ Script.Buginese, "Bugi"}, |
|||
{ Script.Buhid, "Buhd"}, |
|||
{ Script.Chakma, "Cakm"}, |
|||
{ Script.CanadianAboriginal, "Cans"}, |
|||
{ Script.Carian, "Cari"}, |
|||
{ Script.Cham, "Cham"}, |
|||
{ Script.Cherokee, "Cher"}, |
|||
{ Script.Chorasmian, "Chrs"}, |
|||
{ Script.Coptic, "Copt"}, |
|||
{ Script.Cypriot, "Cprt"}, |
|||
{ Script.Cyrillic, "Cyrl"}, |
|||
{ Script.Devanagari, "Deva"}, |
|||
{ Script.DivesAkuru, "Diak"}, |
|||
{ Script.Dogra, "Dogr"}, |
|||
{ Script.Deseret, "Dsrt"}, |
|||
{ Script.Duployan, "Dupl"}, |
|||
{ Script.EgyptianHieroglyphs, "Egyp"}, |
|||
{ Script.Elbasan, "Elba"}, |
|||
{ Script.Elymaic, "Elym"}, |
|||
{ Script.Ethiopic, "Ethi"}, |
|||
{ Script.Georgian, "Geor"}, |
|||
{ Script.Glagolitic, "Glag"}, |
|||
{ Script.GunjalaGondi, "Gong"}, |
|||
{ Script.MasaramGondi, "Gonm"}, |
|||
{ Script.Gothic, "Goth"}, |
|||
{ Script.Grantha, "Gran"}, |
|||
{ Script.Greek, "Grek"}, |
|||
{ Script.Gujarati, "Gujr"}, |
|||
{ Script.Gurmukhi, "Guru"}, |
|||
{ Script.Hangul, "Hang"}, |
|||
{ Script.Han, "Hani"}, |
|||
{ Script.Hanunoo, "Hano"}, |
|||
{ Script.Hatran, "Hatr"}, |
|||
{ Script.Hebrew, "Hebr"}, |
|||
{ Script.Hiragana, "Hira"}, |
|||
{ Script.AnatolianHieroglyphs, "Hluw"}, |
|||
{ Script.PahawhHmong, "Hmng"}, |
|||
{ Script.NyiakengPuachueHmong, "Hmnp"}, |
|||
{ Script.KatakanaOrHiragana, "Hrkt"}, |
|||
{ Script.OldHungarian, "Hung"}, |
|||
{ Script.OldItalic, "Ital"}, |
|||
{ Script.Javanese, "Java"}, |
|||
{ Script.KayahLi, "Kali"}, |
|||
{ Script.Katakana, "Kana"}, |
|||
{ Script.Kharoshthi, "Khar"}, |
|||
{ Script.Khmer, "Khmr"}, |
|||
{ Script.Khojki, "Khoj"}, |
|||
{ Script.KhitanSmallScript, "Kits"}, |
|||
{ Script.Kannada, "Knda"}, |
|||
{ Script.Kaithi, "Kthi"}, |
|||
{ Script.TaiTham, "Lana"}, |
|||
{ Script.Lao, "Laoo"}, |
|||
{ Script.Latin, "Latn"}, |
|||
{ Script.Lepcha, "Lepc"}, |
|||
{ Script.Limbu, "Limb"}, |
|||
{ Script.LinearA, "Lina"}, |
|||
{ Script.LinearB, "Linb"}, |
|||
{ Script.Lisu, "Lisu"}, |
|||
{ Script.Lycian, "Lyci"}, |
|||
{ Script.Lydian, "Lydi"}, |
|||
{ Script.Mahajani, "Mahj"}, |
|||
{ Script.Makasar, "Maka"}, |
|||
{ Script.Mandaic, "Mand"}, |
|||
{ Script.Manichaean, "Mani"}, |
|||
{ Script.Marchen, "Marc"}, |
|||
{ Script.Medefaidrin, "Medf"}, |
|||
{ Script.MendeKikakui, "Mend"}, |
|||
{ Script.MeroiticCursive, "Merc"}, |
|||
{ Script.MeroiticHieroglyphs, "Mero"}, |
|||
{ Script.Malayalam, "Mlym"}, |
|||
{ Script.Modi, "Modi"}, |
|||
{ Script.Mongolian, "Mong"}, |
|||
{ Script.Mro, "Mroo"}, |
|||
{ Script.MeeteiMayek, "Mtei"}, |
|||
{ Script.Multani, "Mult"}, |
|||
{ Script.Myanmar, "Mymr"}, |
|||
{ Script.Nandinagari, "Nand"}, |
|||
{ Script.OldNorthArabian, "Narb"}, |
|||
{ Script.Nabataean, "Nbat"}, |
|||
{ Script.Newa, "Newa"}, |
|||
{ Script.Nko, "Nkoo"}, |
|||
{ Script.Nushu, "Nshu"}, |
|||
{ Script.Ogham, "Ogam"}, |
|||
{ Script.OlChiki, "Olck"}, |
|||
{ Script.OldTurkic, "Orkh"}, |
|||
{ Script.Oriya, "Orya"}, |
|||
{ Script.Osage, "Osge"}, |
|||
{ Script.Osmanya, "Osma"}, |
|||
{ Script.Palmyrene, "Palm"}, |
|||
{ Script.PauCinHau, "Pauc"}, |
|||
{ Script.OldPermic, "Perm"}, |
|||
{ Script.PhagsPa, "Phag"}, |
|||
{ Script.InscriptionalPahlavi, "Phli"}, |
|||
{ Script.PsalterPahlavi, "Phlp"}, |
|||
{ Script.Phoenician, "Phnx"}, |
|||
{ Script.Miao, "Plrd"}, |
|||
{ Script.InscriptionalParthian, "Prti"}, |
|||
{ Script.Rejang, "Rjng"}, |
|||
{ Script.HanifiRohingya, "Rohg"}, |
|||
{ Script.Runic, "Runr"}, |
|||
{ Script.Samaritan, "Samr"}, |
|||
{ Script.OldSouthArabian, "Sarb"}, |
|||
{ Script.Saurashtra, "Saur"}, |
|||
{ Script.SignWriting, "Sgnw"}, |
|||
{ Script.Shavian, "Shaw"}, |
|||
{ Script.Sharada, "Shrd"}, |
|||
{ Script.Siddham, "Sidd"}, |
|||
{ Script.Khudawadi, "Sind"}, |
|||
{ Script.Sinhala, "Sinh"}, |
|||
{ Script.Sogdian, "Sogd"}, |
|||
{ Script.OldSogdian, "Sogo"}, |
|||
{ Script.SoraSompeng, "Sora"}, |
|||
{ Script.Soyombo, "Soyo"}, |
|||
{ Script.Sundanese, "Sund"}, |
|||
{ Script.SylotiNagri, "Sylo"}, |
|||
{ Script.Syriac, "Syrc"}, |
|||
{ Script.Tagbanwa, "Tagb"}, |
|||
{ Script.Takri, "Takr"}, |
|||
{ Script.TaiLe, "Tale"}, |
|||
{ Script.NewTaiLue, "Talu"}, |
|||
{ Script.Tamil, "Taml"}, |
|||
{ Script.Tangut, "Tang"}, |
|||
{ Script.TaiViet, "Tavt"}, |
|||
{ Script.Telugu, "Telu"}, |
|||
{ Script.Tifinagh, "Tfng"}, |
|||
{ Script.Tagalog, "Tglg"}, |
|||
{ Script.Thaana, "Thaa"}, |
|||
{ Script.Thai, "Thai"}, |
|||
{ Script.Tibetan, "Tibt"}, |
|||
{ Script.Tirhuta, "Tirh"}, |
|||
{ Script.Ugaritic, "Ugar"}, |
|||
{ Script.Vai, "Vaii"}, |
|||
{ Script.WarangCiti, "Wara"}, |
|||
{ Script.Wancho, "Wcho"}, |
|||
{ Script.OldPersian, "Xpeo"}, |
|||
{ Script.Cuneiform, "Xsux"}, |
|||
{ Script.Yezidi, "Yezi"}, |
|||
{ Script.Yi, "Yiii"}, |
|||
{ Script.ZanabazarSquare, "Zanb"}, |
|||
}; |
|||
|
|||
public static string GetTag(Script script) |
|||
{ |
|||
if(!s_scriptToTag.ContainsKey(script)) |
|||
{ |
|||
return "Zzzz"; |
|||
} |
|||
return s_scriptToTag[script]; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,424 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Presenters; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Media; |
|||
using Avalonia.UnitTests; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Layout.UnitTests |
|||
{ |
|||
public class LayoutableTests_EffectiveViewportChanged |
|||
{ |
|||
[Fact] |
|||
public async Task EffectiveViewportChanged_Not_Raised_When_Control_Added_To_Tree() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas(); |
|||
var raised = 0; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = target; |
|||
|
|||
Assert.Equal(0, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task EffectiveViewportChanged_Raised_Before_LayoutUpdated() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas(); |
|||
var raised = 0; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = target; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
|
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Parent_Affects_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 100, Height = 100 }; |
|||
var parent = new Border { Width = 200, Height = 200, Child = target }; |
|||
var raised = 0; |
|||
|
|||
root.Child = parent; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(-550, -400, 1200, 900), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Invalidating_In_Handler_Causes_Layout_To_Be_Rerun_Before_LayoutUpdated_Raised() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new TestCanvas(); |
|||
var raised = 0; |
|||
var layoutUpdatedRaised = 0; |
|||
|
|||
root.LayoutUpdated += (s, e) => |
|||
{ |
|||
Assert.Equal(2, target.MeasureCount); |
|||
Assert.Equal(2, target.ArrangeCount); |
|||
++layoutUpdatedRaised; |
|||
}; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
target.InvalidateMeasure(); |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = target; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
|
|||
Assert.Equal(1, raised); |
|||
Assert.Equal(1, layoutUpdatedRaised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Viewport_Extends_Beyond_Centered_Control() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 52, Height = 52, }; |
|||
var raised = 0; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(-574, -424, 1200, 900), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = target; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Viewport_Extends_Beyond_Nested_Centered_Control() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 52, Height = 52 }; |
|||
var parent = new Border { Width = 100, Height = 100, Child = target }; |
|||
var raised = 0; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(-574, -424, 1200, 900), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = parent; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ScrollViewer_Determines_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 200, Height = 200 }; |
|||
var scroller = new ScrollViewer { Width = 100, Height = 100, Content = target, Template = ScrollViewerTemplate() }; |
|||
var raised = 0; |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(0, 0, 100, 100), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
root.Child = scroller; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Scrolled_ScrollViewer_Determines_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 200, Height = 200 }; |
|||
var scroller = new ScrollViewer { Width = 100, Height = 100, Content = target, Template = ScrollViewerTemplate() }; |
|||
var raised = 0; |
|||
|
|||
root.Child = scroller; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
scroller.Offset = new Vector(0, 10); |
|||
|
|||
await ExecuteScrollerLayoutPass(root, scroller, target, (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(0, 10, 100, 100), e.EffectiveViewport); |
|||
++raised; |
|||
}); |
|||
|
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Moving_Parent_Updates_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 100, Height = 100 }; |
|||
var parent = new Border { Width = 200, Height = 200, Child = target }; |
|||
var raised = 0; |
|||
|
|||
root.Child = parent; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(-554, -400, 1200, 900), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
parent.Margin = new Thickness(8, 0, 0, 0); |
|||
await ExecuteLayoutPass(root); |
|||
|
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Translate_Transform_Doesnt_Affect_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 100, Height = 100 }; |
|||
var parent = new Border { Width = 200, Height = 200, Child = target }; |
|||
var raised = 0; |
|||
|
|||
root.Child = parent; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
target.EffectiveViewportChanged += (s, e) => ++raised; |
|||
target.RenderTransform = new TranslateTransform { X = 8 }; |
|||
target.InvalidateMeasure(); |
|||
await ExecuteLayoutPass(root); |
|||
|
|||
Assert.Equal(0, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Translate_Transform_On_Parent_Affects_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 100, Height = 100 }; |
|||
var parent = new Border { Width = 200, Height = 200, Child = target }; |
|||
var raised = 0; |
|||
|
|||
root.Child = parent; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
Assert.Equal(new Rect(-558, -400, 1200, 900), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
// Change the parent render transform to move it. A layout is then needed before
|
|||
// EffectiveViewportChanged is raised.
|
|||
parent.RenderTransform = new TranslateTransform { X = 8 }; |
|||
parent.InvalidateMeasure(); |
|||
await ExecuteLayoutPass(root); |
|||
|
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Rotate_Transform_On_Parent_Affects_EffectiveViewport() |
|||
{ |
|||
await RunOnUIThread.Execute(async () => |
|||
{ |
|||
var root = CreateRoot(); |
|||
var target = new Canvas { Width = 100, Height = 100 }; |
|||
var parent = new Border { Width = 200, Height = 200, Child = target }; |
|||
var raised = 0; |
|||
|
|||
root.Child = parent; |
|||
|
|||
await ExecuteInitialLayoutPass(root); |
|||
|
|||
target.EffectiveViewportChanged += (s, e) => |
|||
{ |
|||
AssertArePixelEqual(new Rect(-651, -792, 1484, 1484), e.EffectiveViewport); |
|||
++raised; |
|||
}; |
|||
|
|||
parent.RenderTransformOrigin = new RelativePoint(0, 0, RelativeUnit.Absolute); |
|||
parent.RenderTransform = new RotateTransform { Angle = 45 }; |
|||
parent.InvalidateMeasure(); |
|||
await ExecuteLayoutPass(root); |
|||
|
|||
Assert.Equal(1, raised); |
|||
}); |
|||
} |
|||
|
|||
private TestRoot CreateRoot() => new TestRoot { Width = 1200, Height = 900 }; |
|||
|
|||
private Task ExecuteInitialLayoutPass(TestRoot root) |
|||
{ |
|||
root.LayoutManager.ExecuteInitialLayoutPass(); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
private Task ExecuteLayoutPass(TestRoot root) |
|||
{ |
|||
root.LayoutManager.ExecuteLayoutPass(); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
private Task ExecuteScrollerLayoutPass( |
|||
TestRoot root, |
|||
ScrollViewer scroller, |
|||
Control target, |
|||
Action<object, EffectiveViewportChangedEventArgs> handler) |
|||
{ |
|||
void ViewportChanged(object sender, EffectiveViewportChangedEventArgs e) |
|||
{ |
|||
handler(sender, e); |
|||
} |
|||
|
|||
target.EffectiveViewportChanged += ViewportChanged; |
|||
root.LayoutManager.ExecuteLayoutPass(); |
|||
return Task.CompletedTask; |
|||
} |
|||
private IControlTemplate ScrollViewerTemplate() |
|||
{ |
|||
return new FuncControlTemplate<ScrollViewer>((control, scope) => new Grid |
|||
{ |
|||
ColumnDefinitions = new ColumnDefinitions |
|||
{ |
|||
new ColumnDefinition(1, GridUnitType.Star), |
|||
new ColumnDefinition(GridLength.Auto), |
|||
}, |
|||
RowDefinitions = new RowDefinitions |
|||
{ |
|||
new RowDefinition(1, GridUnitType.Star), |
|||
new RowDefinition(GridLength.Auto), |
|||
}, |
|||
Children = |
|||
{ |
|||
new ScrollContentPresenter |
|||
{ |
|||
Name = "PART_ContentPresenter", |
|||
[~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty], |
|||
[~~ScrollContentPresenter.ExtentProperty] = control[~~ScrollViewer.ExtentProperty], |
|||
[~~ScrollContentPresenter.OffsetProperty] = control[~~ScrollViewer.OffsetProperty], |
|||
[~~ScrollContentPresenter.ViewportProperty] = control[~~ScrollViewer.ViewportProperty], |
|||
[~ScrollContentPresenter.CanHorizontallyScrollProperty] = control[~ScrollViewer.CanHorizontallyScrollProperty], |
|||
[~ScrollContentPresenter.CanVerticallyScrollProperty] = control[~ScrollViewer.CanVerticallyScrollProperty], |
|||
}.RegisterInNameScope(scope), |
|||
new ScrollBar |
|||
{ |
|||
Name = "horizontalScrollBar", |
|||
Orientation = Orientation.Horizontal, |
|||
[~RangeBase.MaximumProperty] = control[~ScrollViewer.HorizontalScrollBarMaximumProperty], |
|||
[~~RangeBase.ValueProperty] = control[~~ScrollViewer.HorizontalScrollBarValueProperty], |
|||
[~ScrollBar.ViewportSizeProperty] = control[~ScrollViewer.HorizontalScrollBarViewportSizeProperty], |
|||
[~ScrollBar.VisibilityProperty] = control[~ScrollViewer.HorizontalScrollBarVisibilityProperty], |
|||
[Grid.RowProperty] = 1, |
|||
}.RegisterInNameScope(scope), |
|||
new ScrollBar |
|||
{ |
|||
Name = "verticalScrollBar", |
|||
Orientation = Orientation.Vertical, |
|||
[~RangeBase.MaximumProperty] = control[~ScrollViewer.VerticalScrollBarMaximumProperty], |
|||
[~~RangeBase.ValueProperty] = control[~~ScrollViewer.VerticalScrollBarValueProperty], |
|||
[~ScrollBar.ViewportSizeProperty] = control[~ScrollViewer.VerticalScrollBarViewportSizeProperty], |
|||
[~ScrollBar.VisibilityProperty] = control[~ScrollViewer.VerticalScrollBarVisibilityProperty], |
|||
[Grid.ColumnProperty] = 1, |
|||
}.RegisterInNameScope(scope), |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
private void AssertArePixelEqual(Rect expected, Rect actual) |
|||
{ |
|||
var expectedRounded = new Rect((int)expected.X, (int)expected.Y, (int)expected.Width, (int)expected.Height); |
|||
var actualRounded = new Rect((int)actual.X, (int)actual.Y, (int)actual.Width, (int)actual.Height); |
|||
Assert.Equal(expectedRounded, actualRounded); |
|||
} |
|||
|
|||
private class TestCanvas : Canvas |
|||
{ |
|||
public int MeasureCount { get; private set; } |
|||
public int ArrangeCount { get; private set; } |
|||
|
|||
protected override Size MeasureOverride(Size availableSize) |
|||
{ |
|||
++MeasureCount; |
|||
return base.MeasureOverride(availableSize); |
|||
} |
|||
|
|||
protected override Size ArrangeOverride(Size finalSize) |
|||
{ |
|||
++ArrangeCount; |
|||
return base.ArrangeOverride(finalSize); |
|||
} |
|||
} |
|||
|
|||
private static class RunOnUIThread |
|||
{ |
|||
public static async Task Execute(Func<Task> func) |
|||
{ |
|||
await func(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +1,34 @@ |
|||
OP CL CP QU GL NS EX SY IS PR PO NU AL HL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT RI EB EM ZWJ |
|||
OP ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ @ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ |
|||
CL _ ^ ^ % % ^ ^ ^ ^ % % _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
CP _ ^ ^ % % ^ ^ ^ ^ % % % % % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
QU ^ ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % |
|||
GL % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % |
|||
NS _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
EX _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
SY _ ^ ^ % % % ^ ^ ^ _ _ % _ % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
IS _ ^ ^ % % % ^ ^ ^ _ _ % % % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
PR % ^ ^ % % % ^ ^ ^ _ _ % % % % _ % % _ _ ^ # ^ % % % % % _ % % % |
|||
PO % ^ ^ % % % ^ ^ ^ _ _ % % % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
NU % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
AL % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
HL % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
ID _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
IN _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
HY _ ^ ^ % _ % ^ ^ ^ _ _ % _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
BA _ ^ ^ % _ % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
BB % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % |
|||
B2 _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ ^ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
ZW _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ^ _ _ _ _ _ _ _ _ _ _ _ |
|||
CM % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
WJ % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % |
|||
H2 _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ % % _ _ _ % |
|||
H3 _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ % _ _ _ % |
|||
JL _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ % % % % _ _ _ _ % |
|||
JV _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ % % _ _ _ % |
|||
JT _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ % _ _ _ % |
|||
RI _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ % _ _ % |
|||
EB _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ % % |
|||
EM _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % |
|||
ZWJ _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ % _ % % _ _ ^ # ^ _ _ _ _ _ _ % % % |
|||
OP CL CP QU GL NS EX SY IS PR PO NU AL HL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT RI EB EM ZWJ CB |
|||
OP ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ @ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ |
|||
CL _ ^ ^ % % ^ ^ ^ ^ % % _ _ _ _ ^ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
CP _ ^ ^ % % ^ ^ ^ ^ % % % % % _ ^ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
QU ^ ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % % |
|||
GL % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % % |
|||
NS _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
EX _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
SY _ ^ ^ % % % ^ ^ ^ _ _ % _ % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
IS _ ^ ^ % % % ^ ^ ^ _ _ % % % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
PR % ^ ^ % % % ^ ^ ^ _ _ % % % % _ % % _ _ ^ # ^ % % % % % _ % % % _ |
|||
PO % ^ ^ % % % ^ ^ ^ _ _ % % % _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
NU % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
AL % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
HL % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
ID _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
IN _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
HY _ ^ ^ % _ % ^ ^ ^ _ _ % _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
BA _ ^ ^ % _ % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
BB % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % _ |
|||
B2 _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ ^ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
ZW _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ^ _ _ _ _ _ _ _ _ _ _ _ _ |
|||
CM % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
WJ % ^ ^ % % % ^ ^ ^ % % % % % % % % % % % ^ # ^ % % % % % % % % % % |
|||
H2 _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ % % _ _ _ % _ |
|||
H3 _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ % _ _ _ % _ |
|||
JL _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ % % % % _ _ _ _ % _ |
|||
JV _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ % % _ _ _ % _ |
|||
JT _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ % _ _ _ % _ |
|||
RI _ ^ ^ % % % ^ ^ ^ _ _ _ _ _ _ _ % % _ _ ^ # ^ _ _ _ _ _ % _ _ % _ |
|||
EB _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ % % _ |
|||
EM _ ^ ^ % % % ^ ^ ^ _ % _ _ _ _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
ZWJ % ^ ^ % % % ^ ^ ^ % % % % % _ % % % _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
CB _ ^ ^ % % _ ^ ^ ^ _ _ _ _ _ _ _ _ _ _ _ ^ # ^ _ _ _ _ _ _ _ _ % _ |
|||
|
|||
@ -0,0 +1,85 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Net.Http; |
|||
|
|||
namespace Avalonia.Visuals.UnitTests.Media.TextFormatting |
|||
{ |
|||
public abstract class TestDataGenerator : IEnumerable<object[]> |
|||
{ |
|||
private readonly string _fileName; |
|||
private readonly List<object[]> _testData; |
|||
|
|||
protected TestDataGenerator(string fileName) |
|||
{ |
|||
_fileName = fileName; |
|||
_testData = ReadTestData(); |
|||
} |
|||
|
|||
public IEnumerator<object[]> GetEnumerator() |
|||
{ |
|||
return _testData.GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return GetEnumerator(); |
|||
} |
|||
|
|||
private List<object[]> ReadTestData() |
|||
{ |
|||
var testData = new List<object[]>(); |
|||
|
|||
using (var client = new HttpClient()) |
|||
{ |
|||
var url = Path.Combine(UnicodeDataGenerator.Ucd, _fileName); |
|||
|
|||
using (var result = client.GetAsync(url).GetAwaiter().GetResult()) |
|||
{ |
|||
if (!result.IsSuccessStatusCode) |
|||
return testData; |
|||
|
|||
using (var stream = result.Content.ReadAsStreamAsync().GetAwaiter().GetResult()) |
|||
using (var reader = new StreamReader(stream)) |
|||
{ |
|||
while (!reader.EndOfStream) |
|||
{ |
|||
var line = reader.ReadLine(); |
|||
|
|||
if (line == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (line.StartsWith("#") || string.IsNullOrEmpty(line)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var elements = line.Split('#'); |
|||
|
|||
elements = elements[0].Replace("÷\t", "÷").Trim('÷').Split('÷'); |
|||
|
|||
var chars = elements[0].Replace(" × ", " ").Split(' '); |
|||
|
|||
var codepoints = chars.Where(x => x != "" && x != "×") |
|||
.Select(x => Convert.ToInt32(x, 16)).ToArray(); |
|||
|
|||
var text = string.Join(null, codepoints.Select(char.ConvertFromUtf32)); |
|||
|
|||
var length = codepoints.Select(x => x > ushort.MaxValue ? 2 : 1).Sum(); |
|||
|
|||
var data = new object[] { text, length }; |
|||
|
|||
testData.Add(data); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return testData; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue