Branch:
main
0.10.0-diff-stable-0.9.11
0.8-backports
0.8-work
0.9/xamlx
5940-dragdrop-modal
7963-stable
Blaz
MikeCodesDotNET-coc-update
NumericUpDown_Fix_5318
Stylus
UnsafeAsSpan-logical-children
about-dialog-redesign
add-expanderAutomationPeer
add-integration-tests
add-missing-type-converters
add-remote-designer-test
android-profile
android_clipboard
android_naot
android_native_window_crash
android_previewer
android_text_client
animation-fill-modes-test
animations-property-path
aot-test-pipeline
api-diff-demo
appium2-vm-test
archive/wieslop-pr-to-prevent-him-from-deleting-the-repo-again-and-claiming-that-stuff-didnt-happen
attach-dev-tools-conditional
attempt-datacontext-application-class
backport-11096
backports/19939
backup/fixes/catalina-red-window-15-16-08
baget-ci-test
border-clip-test
bug/focus-within-not-cleared
bump-diagnosticssupport
castxml-0.2
chart-control
china
codefreeze-0.7
codice/preview4-plus-10064
comp-size-implicitanim-repro
compile-bindings-by-default-property
composition/license
consistent-names
context-menu-refactor
control-theme-idea
critical-time-visual
customers/chaos-11.0
customers/outsystems-11.1.X
customers/outsystems-11.1.x-without-2-prs-for-testing
customers/outsystems-11.2
customers/outsystems-branches/11.2-test-port-19132
customers/outsystems/11.2-test-port-19132
customers/se-eae
dans-repro
dans-repro-without-1284
datagrid-combobox-column
dbus-tray-icon-fix-2
debug-wasm-clicks
debug/gl-texture-mem-intercept
debug/skia-sharp-vmem
demo
demo1
designer_protocol_theme_variant
dev/timill/EglExternalObjectsFeature
dev/timill/catalyst
dev/timill/dma-buf
dev/timill/egl-take-two
dev/timill/macos-setup-app
dev/timill/metal
dev/timill/skiasharp-4-test
dev/timill/styles-animation
dev/timill/win-arm64-build
dev/timill/window-decorations-macos
dev/timill/winui-test
diagnose-ci
direct-comp-archive
disbar
dispatcher-scheduler
do-not-sign-rxui-attempt-2
doc-fixes
dont-self-register-font-manager
drawing-context-hack
droid
effective_viewport_bug_repro
emmaus/gradient_test
empty_text_run_fix
event-setter
exp/drawn-decorations-template
experiment-alpha-niner
experiment/fixing-key-events-macos-embedding
experiment/lazy-load-styles-resources
experiment/merged-fluent-theme
experiment/reflection-free
experiment/skia-known-extensions
experiment/styleinclude-filter
experiments/vulkan-interop-2025-10-29
expose-cut-copy-paste-textbox
feature-presentation-source-2
feature/17731-null-conditional-bindings
feature/2769-control-themes
feature/3109-listen
feature/ImePreeditText
feature/acrylic-brush-investigation
feature/add-get-pixels-to-IBitmapImpl
feature/backdrop-effects
feature/backdrop-experiment
feature/background-fb-transfer
feature/client-frame-in-titlebar
feature/composition-swapchain
feature/composition-tree-inspector
feature/crapium
feature/custom-visual-oob-message
feature/custom-visual-sync
feature/drawn-csd-template
feature/epoll-dispatcher-impl
feature/extract-harfbuzz
feature/flaui-webdriver
feature/fluent-calendar
feature/fluent-scrollbar
feature/fluent-slider
feature/fluent-slider-template
feature/fluent-text-box
feature/flyout-overlayinputpassthrough
feature/flyouts
feature/forced-csd
feature/fullscreen-window-state
feature/gh-actions
feature/gpu-improvements
feature/headless-touch
feature/heterogeneous-item-containers
feature/icons
feature/ilogicalvisualchildren
feature/integer-clip-bak-1
feature/integration-tests-vm-migration
feature/linux-automation
feature/linux-automation-backup
feature/managed-chrome-buttons-api
feature/media-queries
feature/microcom-get-managed-reference
feature/offthread-composition-interop
feature/opengl-image-api
feature/opengl-swapchain
feature/optimized-matrix
feature/pass-shadow-extents-to-platform
feature/pen-eraser-detection
feature/pluggable-input-methods
feature/presentation-source-2
feature/public-frost
feature/remove-legacy-renderers
feature/render-inside-windows-ui-composition-visual-tree
feature/render-thread-transparency
feature/resource-batch-update
feature/save-render-frames
feature/skia-cpu-copy
feature/staggeredlayout
feature/support-more-image-formats
feature/test-branch
feature/textbox-gestures-mac-cmd+
feature/typed-binding-2
feature/typedbinding
feature/ui-automation-atspi
feature/ui-automation-textprovider
feature/ui-automation-textprovider-2
feature/validate-draw-calls
feature/vulkan
feature/wayland-deps
feature/wayland-subcompositor
feature/wd/platform-specific-cookies-pointer-events
feature/windowstate-fullscreen
feature/wmt
feature/writablebitmap-drawingcontext
feature/x11-ime-preedit
feature/x11-incr
feature/x11-primary-selection
features/atspi-peering-mode
features/dbus+atspi2+kdeappiumdriver
features/instant-dark-light-mode-switch
features/manually-managed-layer-textures
features/modal-windows
features/net6-apple-sillicon-support
features/prep1-nullable-reference-types
fies/15433-itemscontrol-interactions-to-containers
fix-ci
fix-mac-special-character-input
fix-mousedevice-not-reporting-clicks-when-any-mouse-button-is-pressed
fix-popup-topmost-windows
fix-windowicon-crash-linuxdrm
fix/DataGridCopyClearsContent
fix/avnview-hittest
fix/ibus-committext-reset
fix/osx-ax-frame-window
fix/osx-ax-honor-ignored-elements
fix/osx-ax-offscreen-noncontrol-children
fix/osx-ax-visible-children
fix/render-stall
fix_colors_change_event_spam
fixes-data-validation-errors-use-datatemplates
fixes/11167-pagetransition-flicker
fixes/11484-coercevalue-called-multiple-times
fixes/1399-dispatchertimer-disposable
fixes/1440-menu-navigation
fixes/1758-implement-non-recycling-virtualization-mode
fixes/17699-uniformgrid-snapping
fixes/20845-tabitem-datacontext-binding-2
fixes/2129-grid-textwrapping
fixes/21746-update-target-explicit
fixes/2725-datatemplate-nested-types
fixes/2957-carousel-stackoverflow
fixes/2983-onewaytosource-twoway
fixes/4293-listbox-remove-item-selection
fixes/4496-selectionmodel-issues
fixes/6684-two-way-style-bindings-with-localvalue
fixes/7777-menu-accelerator
fixes/7925-attached-property-syntax
fixes/9007-priority-in-control-templates
fixes/971-selector-child-of-named
fixes/PreviewWithv12
fixes/add-fluent-theme-tests-and-several-fixes
fixes/android-perf-maybe
fixes/android-render-issue
fixes/appium2
fixes/automation-localization-issues
fixes/avalonia-win32-nullability
fixes/avdbus-impl2
fixes/build-stable-with-6.0.202
fixes/build-task-update-try-fix
fixes/caret-index-lost-when-selection-cleared
fixes/center-screen-maximized-parent
fixes/clear-batch-object-pool-sooner
fixes/compositing-renderer-invalidatevisual-sanity-checks
fixes/disable-fullscreen-overlay-for-border-only-mode
fixes/disable-fullscreenwindow-tests-osx
fixes/dispatcher-frame-dispatcher
fixes/dont-allow-focus-non-visible-elements
fixes/dragdrop-pointer-stuck
fixes/draw-line-on-deferred-renderer
fixes/effect-clip
fixes/effect-clip-rect
fixes/enable-multi-touch-by-default
fixes/fix-android-perf-maybe-2
fixes/gpu-interop-check-dedicated-allocation-needed
fixes/grcontext-options
fixes/hackfix-skia-gpu-interop
fixes/handle-invalid-dirty-rects
fixes/immutable-bitmap-bitmapmemory-backing
fixes/integration-tests-window-management
fixes/less-warnings
fixes/listbox-selecteditem-not-in-item-ignored
fixes/macos-dont-raise-text-input-if-key-handled
fixes/macos-duplicate-a11y-window
fixes/macos-owned-window-level-inheritance
fixes/macos-uri-handling
fixes/make-iinlinehost-public
fixes/metal-resize-jitter
fixes/microcom-bump
fixes/ncrunch-references
fixes/nsopenpanel-shortcut
fixes/osx-hidden-window-activation
fixes/osx-rendering-glitches
fixes/pendevice-remove-global-state
fixes/publish-avalonia-native-osx-package-seperately
fixes/pump-dispatcher-before-invoking-native-loop
fixes/re-enable-full-sharpgentools
fixes/readd-references-file
fixes/remove-adorner-hack
fixes/remove-loaded-virtual-method
fixes/render-layers
fixes/resizing-wasm
fixes/round-corner-clip-border
fixes/selectionmodel-handle-move
fixes/stable-disable-roll-forward
fixes/stack-overflow-resources
fixes/standalone-content-presenter
fixes/tcc-333
fixes/text-layout
fixes/textLineMetrics
fixes/ticket-745
fixes/tmp
fixes/too-many-layers
fixes/transitions-property-changes
fixes/tree-selectionmodel
fixes/treeview-nonmaterialized-selection
fixes/wasm-layout-render-sync
fixes/win-ui-comp-global-lock
fixes/win32-maximize-not-applied-initially-when-height-set
fixes/window-close-crash
fixes/window-close-crash-testcode
fixes/window-management-stage-manager
fixes/xamlx-generic-type-resolution
fixes/yet-another-dbus-typing-fix
flickerRepo
fluent-textbox-update
focus-and-keyboard
focus_prototype
focus_tree_state
font-tests
force-ci/composition-rework
force-ci/xaml-perf-improvements
foreign-embed-squash
foreign-embed-wip
foreign-embed2
git-pr_6982_rework
global-menu
gpu-optimised-deferred-rendering
grid-tests
grokys/experiment/appium-2
grokys/experiment/appium-2-2
grokys/experiment/more-benchmarks
grokys/experiment/new-itemscontrol
grokys/experiment/new-styling
grokys/framebuffer-skip-memcpy
grokys/trying-to-fix-integration-tests
grokys/update-net-5.0
gtk-solution
hack/emulate-touch-events
headless-tests
headless-timers
html-auto-port
ignore-capture-on-pointer-entered-exited
image-filters
image-scrolling-repro
implement-decorated-window-dragging
inlinesTheThird
integration-tests-selenium
ios-dev
ios-fix
issue-457
itemspresenterbase
jw/native-graphics
jw/wip/wayland
keyframe-binding
knock-knock-are-integration-tests-even-alive
layers-wtf-repro
linux-mono-down
main
managed-dialog-extras-0.9
managed-mouse-pointer
manual-fbo
maxkatz6-patch-1
memory-leak-repro-commit
menu-contexntmenu-slection-is-not-consistant
mergeWithDrawingRecording
microcom-net5-features
missing_content_repro
move
move_resize
nativeMenu-leak-fix
nativeMenuItem-leak-macOS-fix
nativeaot-llvm-experiment
ncomposition
net11-browser
new-weak-events
no-layer-hack
no-llvmpipe
no_composition_rounded
notify-test
old/2025-12-06
onformfactor_issue
open-contextmenu-with-keyboard
opentk-integration
osx-fixes
osx/maximised-set-in-xaml-fix
package-control-catalog
page_proto
parma-fixes-2020-10
pivot_touch
platform_feedback
popup-repro
port/wpf-uniformgrid
portable-xaml
pr4a/fvar-avar-parsing
pr4b/glyph-typeface-with-variation
pr4c/gvar-deformation
pr4d/hvar-advances
pr4f/mvar-metrics
pr4g/vvar-advances
pr4h/font-variations-user-api
pre-lifetime-fixes
property-path
property_transition_stops_repro
psp-repro
pull/14157
rc1-testing
refactor/avaloniapropertystore
refactor/binding-refactor-2025
refactor/binding-to-reflectionbinding
refactor/bindingexpressions-in-valuestore
refactor/bindings-are-expressions
refactor/compiledbinding-refactor-2025
refactor/datavalidation-plugins
refactor/iavaloniaobject-nongeneric
refactor/itemsrepeater-as-itemspresenter
refactor/itemsrepeater-as-itemspresenter2
refactor/layout
refactor/logical-child-optimize
refactor/more-nullable-avalonia-base
refactor/onpropertychanged-nongeneric
refactor/style-priorities
refactor/visual-child-optimize
refactor_pointerover_backportable
release/0.10.0
release/0.10.0-preview1
release/0.10.0-preview2
release/0.10.0-preview3
release/0.10.0-preview4
release/0.10.0-preview5
release/0.10.0-preview6
release/0.10.0-rc1
release/0.10.0-rc2
release/0.10.1
release/0.10.10
release/0.10.11
release/0.10.11-rc.1
release/0.10.11-rc.2
release/0.10.12
release/0.10.13
release/0.10.14
release/0.10.15
release/0.10.16
release/0.10.17
release/0.10.18
release/0.10.19
release/0.10.2
release/0.10.20
release/0.10.21
release/0.10.22
release/0.10.3
release/0.10.4
release/0.10.5
release/0.10.6
release/0.10.7
release/0.10.8
release/0.10.9
release/0.7.0
release/0.8.0
release/0.8.1
release/0.8.2
release/0.8.3
release/0.8.4
release/0.9.0
release/0.9.0-preview1
release/0.9.0-preview10
release/0.9.0-preview2
release/0.9.0-preview3
release/0.9.0-preview4
release/0.9.0-preview5
release/0.9.0-preview6
release/0.9.0-preview7
release/0.9.0-preview8
release/0.9.0-preview9
release/0.9.0-rc.1
release/0.9.0-rc.2
release/0.9.0-rc0001
release/0.9.1
release/0.9.10
release/0.9.11
release/0.9.12
release/0.9.2
release/0.9.3
release/0.9.4
release/0.9.5
release/0.9.6
release/0.9.7
release/0.9.8
release/0.9.8.1
release/0.9.9
release/11.0
release/11.0.0
release/11.0.0-preview1
release/11.0.0-preview2
release/11.0.0-preview3
release/11.0.0-preview4
release/11.0.0-preview5
release/11.0.0-preview6
release/11.0.0-preview7
release/11.0.0-preview8
release/11.0.0-rc1.1
release/11.0.0-rc2.1
release/11.0.0-rc2.2
release/11.0.1
release/11.0.10
release/11.0.11
release/11.0.12
release/11.0.13
release/11.0.2
release/11.0.3
release/11.0.4
release/11.0.5
release/11.0.5-rc1
release/11.0.6
release/11.0.7
release/11.0.8
release/11.0.9
release/11.1
release/11.1.0
release/11.1.0-beta1
release/11.1.0-beta2
release/11.1.0-rc1
release/11.1.0-rc2
release/11.1.1
release/11.1.2
release/11.1.3
release/11.1.4
release/11.1.5
release/11.2
release/11.2.0
release/11.2.0-beta1
release/11.2.0-beta2
release/11.2.0-rc1
release/11.2.0-rc2
release/11.2.1
release/11.2.2
release/11.2.3
release/11.2.4
release/11.2.5
release/11.2.6
release/11.2.7
release/11.2.8
release/11.3
release/11.3.0
release/11.3.0-beta1
release/11.3.0-beta2
release/11.3.0-rc1
release/11.3.1
release/11.3.10
release/11.3.11
release/11.3.12
release/11.3.13
release/11.3.14
release/11.3.15
release/11.3.16
release/11.3.17
release/11.3.18
release/11.3.19
release/11.3.2
release/11.3.20
release/11.3.21
release/11.3.22
release/11.3.3
release/11.3.4
release/11.3.5
release/11.3.6
release/11.3.7
release/11.3.8
release/11.3.9
release/12.0
release/12.0.0
release/12.0.0-preview1
release/12.0.0-preview2
release/12.0.0-rc1
release/12.0.0-rc2
release/12.0.1
release/12.0.2
release/12.0.3
release/12.0.4
release/12.0.5
release/12.1
release/12.1.0
release/12.1.1
release/12.1.2
release/latest
release/outsystems/0.9.11
remote-devtools
remove-acrylic-blur-from-old-win
removing-compositional-renderer-license
render-only-on-render-thread
repro-ap
repro-ap-1
repro-arcsegment-not-updating
repro-binding-window-state
repro-bindingprio-bug
repro-garbled-graphics
repro-ienumerable-menu-navigation
repro-invalid-draw-calls
repro-items-repeater-issue
repro-properties
repro-req-an-frame
repro-resource-recursion
repro-selected-items-not-working
repro-selecting-items-control-not-working-inside-popup
repro-window-close
repro/1326-data-binding-issue
repro/1436-layout-not-done-after-style-applied
repro/1707-listbox-virtualization-resize-performance
repro/1758-virtualizer-measured-items
repro/18104-drag-drop-flyout-placement
repro/20845-tabitem-datacontext-binding
repro/binding-attached-property-from-style
repro/binding-isfocused
repro/bound-listboxes
repro/caret-binding-failure
repro/carousel-not-materializing-content
repro/dynamic-resource-bug
repro/minimal-repro-stackoverflow-onewaytosource-binding
repro/outsys-sizing-issue
repro/properties-overhaul-bug
repro/radial-gradient-transform
repro/size-to-content
repro/window-not-obey-min-height
repros/content-presenter-regression
repros/custom-fonts-pr
repros/text-alignment-issue
repros/web-null-signature
revert-10284-feature/impl-IReadableBitmapImpl-in-SurfaceRenderTarget
revert-13066-fixes/13064-logical-scrollable
revert-14106
revert-18343-bump-dbus-stack
revert-2489-fixes/2432-carousel-insert
revert-2645-issue2613
revert-3221-undecorated-window
revert-selectionmodel
rtb-gl-fixes
scenegraph-after-breakage
scroll-measure
scroll_transition_repro
sdks-update
set-empty-x11-title-instead-of-null
simplify-testing
size-to-content-render-repro
skia-foreign-bitmap
sound
stable-test-mac-os-fix
stable/0.10.0
stable/0.10.x
stable/0.10.x-codice
stable/0.10.x-outsys
stable/0.10.x-se
stable/0.9
stable/outsystems-0.9
stable/parm-0.9
stable/tmp8
strongname
stx/0-preedit-reentrancy
stx/1-text-navigation
stx/10-macos-nstextinputclient
stx/11-android-inputconnection
stx/12-ios-responder
stx/13-win32-tsf
stx/2-automation-text-provider
stx/3-uia-text-pattern
stx/4-atspi-text
stx/5-grid-table-patterns
stx/6-structured-text-input
stx/7-composition-in-document
stx/9-win32-imm
styleable-grid-rowcoldefs
styles-not-getting-applied-repro
system-xaml
tabcontrol-bound-items
temp/implement-hdr
temp/rpi-slowness
temp/testbuild-skia-extensions
test-log-box-shadow
test-meta-packages
test-multiple-optimizations-together
test-package-run
test-saverestore-layer
test-styleable-rowcol-defs
test-sub-menu-item
test/suppressActivationEvents
test/trigger
test11
tests/animations-p1
tests/default-font-fail-nativeaot
testy-test
text-input
text_ime_client_direct
text_selector_adorner
text_selector_magnifier
text_selector_zindex
themes/fluent2
thread-issue-repro
timer-overload
tinywm
tmp-2
tmp-angle
tmp-build-dan
tmp-menu-disable
tmp-winuicomp_with_manual_fbo
tmp/11.0
tmp1
tmp4
tmp6
tmp9
transitions-bugfix-deux
transparency-hints-list
treeview-issue-repro
try-critical-branch-bringup-2
try-fix-3336
ui-automation-test
update-avalonia-dbus-submodule
update-submodules
upgrade-angle
use-net7-tizen
v0.8
virtualized_wrappanel
virtualizeing_wrappanel_rc1
virtualizing_grid
visual-extensions-fallback
visualbrush_recreate
vnc-mouse-drag-issue
vnext
wasm_editcontext
win-ui-comp-with-manual-fbo
win32-jitter-hack
win32_client_pos_test
win32_hidden_border_fix_test
win32_mouse_wheel_zoom
window_hide_test
windowing-prototype
windowing-prototype-drag-and-drop
winit-legacy
wip/use-selectionmodel
wip_snappoint_anchor
x11-mit-shm
x11-test-without-render-window
x11_allowed_actions
xaml_composition_animations
xaml_integrated_comp_animations
xamlil-debug-info
xclass-generator
xdatagrid-experiment
xi2-leave-event
xpf-old
xpf/composition-rework-branch
xpf/primary-mouse-device
xpf/screen-fix-21750
xpf_win32_test
xsd-generator
xy-focus-and-tvos
xy-focus-skiasharp-3
0.0.1-alpha
0.1.0-alpha2
0.1.1
0.1.10
0.1.2
0.1.3
0.1.4
0.1.9
0.10.0
0.10.0-preview1
0.10.0-preview2
0.10.0-preview3
0.10.0-preview4
0.10.0-preview5
0.10.0-preview6
0.10.0-rc1
0.10.0-rc2
0.10.0.10
0.10.0.4
0.10.1
0.10.10
0.10.11
0.10.12
0.10.12.23
0.10.13
0.10.13.24
0.10.14
0.10.15
0.10.16
0.10.17
0.10.18
0.10.19
0.10.2
0.10.20
0.10.21
0.10.22
0.10.3
0.10.4
0.10.5
0.10.6
0.10.7
0.10.8
0.10.9
0.2.0-preview
0.2.1-preview
0.3.1-preview
0.4.0
0.4.1
0.5.0
0.5.1
0.7.0
0.8.0
0.8.1
0.8.2
0.8.3
0.8.4
0.9.0
0.9.0-preview1
0.9.1
0.9.10
0.9.11
0.9.12
0.9.2
0.9.2.18
0.9.2.19
0.9.3
0.9.4
0.9.5
0.9.6
0.9.7
0.9.8
0.9.9
1.0.1
1.0.4
1.1.1
1.1.2
1.2.1
1.3.1
1.3.4
1.4.1
1.4.2
1.5.1
1.6.1
10367-checkpoint1
11.0.0
11.0.0-preview1
11.0.0-preview2
11.0.0-preview3
11.0.0-preview4
11.0.0-preview5
11.0.0-preview6
11.0.0-preview7
11.0.0-preview8
11.0.0-rc1.1
11.0.0-rc2.1
11.0.0-rc2.2
11.0.1
11.0.10
11.0.11
11.0.12
11.0.13
11.0.2
11.0.3
11.0.4
11.0.5
11.0.5-rc1
11.0.6
11.0.7
11.0.8
11.0.9
11.1.0
11.1.0-beta1
11.1.0-beta2
11.1.0-rc1
11.1.0-rc2
11.1.1
11.1.2
11.1.2-rc1
11.1.3
11.1.4
11.1.5
11.2.0
11.2.0-beta1
11.2.0-beta2
11.2.0-rc1
11.2.0-rc2
11.2.1
11.2.2
11.2.3
11.2.4
11.2.5
11.2.6
11.2.7
11.2.8
11.3.0
11.3.0-beta1
11.3.0-beta2
11.3.0-rc1
11.3.1
11.3.10
11.3.11
11.3.12
11.3.13
11.3.14
11.3.15
11.3.16
11.3.17
11.3.18
11.3.19
11.3.2
11.3.20
11.3.21
11.3.22
11.3.3
11.3.4
11.3.5
11.3.6
11.3.7
11.3.8
11.3.9
12.0.0
12.0.0-preview1
12.0.0-preview2
12.0.0-rc1
12.0.0-rc2
12.0.1
12.0.2
12.0.3
12.0.4
12.0.5
12.1.0
12.1.1
12.1.2
itemssource-checkpoint1
itemssource-checkpoint2
nuget-0.7.1.5
nuget-0.7.1.6
nuget-release-0.5.1
nuget-release-0.6.0
nuget-release-0.6.1
${ noResults }
824 Commits (main)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
082a03b7c4
|
Handle DataValidationError notifications returned by ConvertBack (#22171)
* Handle DataValidationError notifications returned by ConvertBack A converter returning a BindingNotification with DataValidationError fell through to the target type converter, which replaced it with a cast error that stringified the notification. Publish the original error instead. * Add additional failing tests. There are more `BindingNotification` cases to handle. * Handle the other `BindingNotification` cases. --------- Co-authored-by: grokys <grokys@users.noreply.github.com> |
7 days ago |
|
|
fedb14ce85
|
Short-circuit a null-conditional operator after a cast (#22174)
Follow-up to #22082, which added the short-circuit to the property accessor nodes. The cast nodes still called ValidateNonNullSource, so a cast reported "Value is null" before the following ?. could suppress it. Casting null now produces null, as in C#, leaving any error to the member access that follows. |
1 week ago |
|
|
8057428233
|
Allow casting to a nested type in a binding path (#22173)
The binding path parser built type names with ParseIdentifier, which doesn't accept '+', so a cast like ((local:Outer+Nested)DataContext) stopped parsing at the '+' and then failed expecting a ')'. Parse type names with a variant that accepts '+'. Ordinary identifiers are unchanged. |
1 week ago |
|
|
acc1494308
|
Consolidate the Unicode segmentation trie and add UAX-29 sentence segmentation (#21875)
* Pack the segmentation properties into one Unicode trie Grapheme, indic-conjunct, word, line and sentence break classes now share a single SegmentationTrie, together with the Emoji, Emoji_Presentation and Default_Ignorable_Code_Point flags that rode in the grapheme word. The UnicodeDataTrie word keeps general category, script and script extensions. - SegmentationTrieGenerator replaces GraphemeBreakClassTrieGenerator and emits Segmentation.trie.cs; UnicodeData.trie.cs is regenerated without the break fields it no longer carries. - SentenceBreakClass data and Codepoint.SentenceBreakClass expose UAX-29 sentence classes to callers. - WordSegment carries the source text slice alongside the code-unit and code-point readouts, matching the shape newer segment types use; the existing constructor and members stay for compatibility. Data regenerated against UCD 17.0.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add UAX-29 sentence segmentation SentenceBreakEnumerator walks sentence boundaries over a UTF-16 span (rules SB1-SB11 and SB998), yielding SentenceSegment values of offset plus text slice. Sentence is the one segmentation granularity accessibility clients and IME navigation ask for that had no implementation, so callers had to approximate it with punctuation heuristics. The conformance suite runs against the Unicode SentenceBreakTest.txt data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Make sentence segmentation linear in the text length Every rule that needed left-hand context rescanned the text backwards from the current position, so a run of spaces or closing brackets was walked once per character in it. Enumerating 40k spaces took 5.5 s; 40k closing brackets took 8.1 s, and both grew quadratically. - Fold the left-hand context into the enumerator as it advances: the last two significant classes for SB6/SB7, and a stage counter over the (STerm | ATerm) Close* Sp* (Sep | CR | LF)? grammar for SB8-SB11. - Memoize the SB8 lookahead. A scan answers every start position it passed over, so the Close* Sp* run after an ATerm is scanned once, not once per position. - Classify with bitmasks, matching LineBreakEnumerator. Both pathological inputs now finish in 0.1 ms at 40k characters. Output is unchanged: the UCD SentenceBreakTest.txt suite passes, and 1.4M random strings over the break classes segment identically to the previous implementation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Read the word segment length from the property valid for every segment WordSegment.Text is empty for segments built through the code-unit constructor that shipped in 12.1, so Text.Length holds only for segments that come from WordBreakEnumerator. Length is set by both constructors. - Measure the ellipsis break position from Length again. - Say on the Text property itself, where it is read, that it can be empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Benchmark word and sentence segmentation across text shapes The break enumerator benchmark covered three enumerators over random codepoint distributions, which measures trie lookup cost but not the per-character cost of the rules themselves. Long runs of one class are where a segmentation algorithm degrades, and nothing measured them. - Add the sentence enumerator to UnicodeBreakEnumeratorBenchmark. - Add UnicodeSegmentationScalingBenchmark: prose, Han, ZWJ emoji, and runs of spaces, closing punctuation, terminator-plus-spaces and regional indicators, each at two lengths so the cost per character is comparable between them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Document the sentence break classes and trim the break unit SentenceBreakClass is public API with nothing but the UCD aliases to go on, so a caller reading Codepoint.SentenceBreakClass has to consult UAX #29 to learn what a value means or which rule reacts to it. - Describe the type and every member in terms of what the sentence rules do with it, keeping the UCD alias as a trailing comment. - Give SentenceBreakUnit a primary constructor and drop its Codepoint property, which nothing reads now that the class is stored directly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Clean up documentation for SentenceBreakClass Removed remarks from the SentenceBreakClass documentation. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
1 week ago |
|
|
920eaa4a22
|
Carry the regional indicator parity forward instead of recounting it (#22197)
WB15 and WB16 pair regional indicators from the start of their run, and the run was recounted from that start at every indicator, so word segmentation was quadratic in the length of an unbroken run of flags. One pass over 4096 flags took 140 ms; the same text with a space between each flag took 121 us. - Track whether an odd number of regional indicators precedes the position the walk has reached, updating it as each code point is consumed. - Drop CountRegionalIndicatorsBefore, which was the only backward scan in the enumerator not bounded by the first significant code point. - Cover the pairing rules: even and odd runs, a run reached after a letter, a run split by a space, and a combining mark inside a flag. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
1 week ago |
|
|
0dbce40347
|
Add RelativeTransform to brushes (#21881)
* Apply tile brush transforms once the tile sits in target space Brush.Transform was concatenated into the shader matrix before the translation that moves the tile onto the painted area, so it acted in the tile's own space instead of the target's. A brush transform on a fill away from the origin - the common case, since a relative viewport resolves against the fill's bounds - came out displaced, and WPF, whose behaviour these brushes follow, disagrees. Both tile paths now place the tile first and let the transform act on the result. Where the placement is identity, which is what the existing goldens cover, the matrices are unchanged. The cross suite gains an image brush so the non-scalable path is covered too, plus a smooth ramp fixture: the star line drawing that was the only image asset survives resampling as sparse speckle, which the comparison metric cannot tell apart from a geometry error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Apply the conic gradient transform after its angle The sweep shader carried Angle as its local matrix and pre-concatenated Brush.Transform onto it, so the transform acted on the raw sweep and the angle then turned the result. Every other brush bakes its intrinsic geometry in first and lets the brush transform act on the finished pattern. The visible effect was that a translation moved the gradient in a direction rotated by Angle - 90 instead of the direction asked for. A sweep gradient is fully determined by its centre and angle, so the golden here is checked against the brush with its centre moved by the same offset and no transform: the two renders are pixel-identical, while the previous order is 0.169 rmse away against a 0.022 tolerance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add RelativeTransform to every brush A brush transform expressed in the unit space of the painted bounds, applied before the absolute Transform - WPF's Brush.RelativeTransform. It lets one brush express a bounds-dependent transform, an SVG gradientTransform in objectBoundingBox units for instance, without baking any one consumer's bounds into a matrix, which is what makes a single brush per gradient definition possible. The property sits on IBrush and Brush, so every brush kind carries it and a consumer reads it without a type test. Each immutable brush takes it through a second constructor, leaving the existing signatures alone and marking them for collapse in v13. The gradient brush animator interpolates it alongside Transform, and the composition schema gains it on both brush bases so the value reaches the render thread as a live resource rather than a snapshot. IBrush is NotClientImplementable, so the added member is suppressed for API validation the way earlier additions to those interfaces are. Nothing consumes it yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Consume RelativeTransform in the Skia backend The relative matrix is conjugated into target space at draw time - the unit square maps onto the painted rect, whose origin translation and scale wrap the matrix - and composes before the absolute brush transform. All three gradient kinds and both tile brush paths read it; a solid colour brush has nothing for it to act on, matching WPF. With no relative transform every path reduces to the previous matrices, so existing goldens stay byte-identical. The cross suite compares the result against WPF for the linear and radial gradients, a drawing brush tiled and untiled, an image brush, the composition order against Transform, one brush shared by two differently sized fills, and the solid colour no-op. Goldens under Skia/Media additionally cover the immediate renderer and the GPU backends, which the cross suite does not exercise; each was measured against its WPF counterpart before being committed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
1 week ago |
|
|
27c1ece36c
|
Fix SplineEasing constructor assigning y2 to Y1 (#22169)
|
1 week ago |
|
|
79ff4ff73e
|
[Text] Glyph Outline Part 5/13 - Shaped buffer glyph indices (#21501)
* Fix glyph metrics; expose glyph bounding box GlyphMetrics previously stored the advance in Width/Height, leaving no field for the actual ink bounding box. Correct the contract: - Expand GlyphMetrics with AdvanceWidth / AdvanceHeight (and the bitmap / vertical-layout members XOffset / YOffset / VerticalOriginX/Y, reserved for later population). - Add GlyfTable.TryGetGlyphBounds: an allocation-free, header-only read of the glyph's control-point bounding box (xMin/yMin/xMax/yMax). Empty glyphs return true with zero bounds; out-of-range / short data return false. Composite glyphs use their header bbox without recursion. - TryGetGlyphMetrics (single + batch) now sources advances into AdvanceWidth / AdvanceHeight and the bounding box into Width / Height / XBearing / YBearing via TryGetGlyphBounds. Side bearings fall back to hmtx/vmtx when the glyph has no outline. The previously latent API had one test relying on the old behaviour (Width == advance); it's updated to assert AdvanceWidth. New tests cover TryGetGlyphBounds (range, empty, letter, descriptor parity) and the corrected metrics (advance placement, ink width distinct from advance, empty-glyph advance-without-ink, batch/single parity). * Add glyph-bounds benchmark GlyphBoundsBenchmark (Avalonia.Benchmarks): a BenchmarkDotNet comparison of the table-based bounds read against Skia's SKFont.GetGlyphWidths, in kernel (font pre-created) and per-run variants across 1 / 16 / 256 glyphs, with MemoryDiagnoser. * Add allocation-free batch glyph-bounds path Adds a bounds-only batch reader so ink-bounds computation (the GlyphRunImpl use case, which already has advances from shaping) doesn't pay for advance lookup or per-glyph indirection: - GlyphBounds: internal value type carrying the control-point box. - GlyfTable.GetGlyphBounds / GlyphTypeface.TryGetGlyphBounds: fetch the glyf and loca spans once per batch and read offsets + headers directly via BinaryPrimitives — no per-glyph ReadOnlyMemory.Span conversion, no intermediate Memory.Slice, no nested call chain. LocaTable exposes RawData / IsShortFormat for this. - Batch TryGetGlyphMetrics refactored onto the same span-cached reader. Measured against Skia's SKFont.GetGlyphWidths (bounds-only, in-process BenchmarkDotNet): the table path is faster at every run length (0.06× / 0.32× / 0.66× at 1 / 16 / 256 glyphs) and allocation-free, where Skia allocates 104 B/run for the SKFont. The earlier advance+bounds path via TryGetGlyphMetrics was ~2.2× slower than Skia at 256 glyphs; the bounds-only span-cached path is ~1.5× faster. The benchmark is updated to compare bounds-only on both sides. * Restore System.Buffers.Binary using in GlyfTable The glyf bounds readers (TryGetGlyphBounds / GetGlyphBounds) read the header int16s via BinaryPrimitives. The base pr2 commit trimmed this using as unused there, but it is needed once pr2b adds the bounds code — without it GlyfTable does not compile on this branch. * Clamp glyph bounding-box extents to non-negative GlyphBounds.Width/Height and both TryGetGlyphMetrics overloads computed the ink extent as (xMax - xMin) / (yMax - yMin). A malformed glyf header where xMax < xMin (or yMax < yMin) produced a negative value that, when narrowed to the ushort GlyphMetrics.Width/Height, wrapped to a huge positive extent instead of a safe zero. Clamp the extent to non-negative in GlyphBounds (the single source of truth for both the single and batch metric paths) and route the single TryGetGlyphMetrics path through GlyphBounds so both behave identically. For int16 coordinates the maximum extent is 65535 = ushort.MaxValue, so the clamped value always fits without overflow. Adds GlyphBoundsTests. * Allocate batch glyph-metric buffers only when their source is present Batch TryGetGlyphMetrics unconditionally sized the hMetrics, vMetrics and bounds temporary buffers to glyphIds.Length, even when the font has no hmtx, no vmtx, or no glyf table. For CFF/CFF2 fonts (no glyf) the bounds buffer is never read, and most fonts have no vmtx, so a large batch on such a font heap-allocated a per-glyph array that was pure waste. Size each buffer to zero — a free, empty stackalloc — when its source table is absent, so it only materialises (and only spills to the heap past 256 glyphs) when it will actually be filled and read. * Note the halved loca offsets in the batch bounds reader The short loca format stores every offset divided by two, which is why the batch reader doubles what it reads. LocaTable's single-glyph path already carries that note; the inline decode in the batch path did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Split the batch metrics loop on the glyf branch instead of per glyph The glyf check does not vary across the run, so it belongs above the loop rather than inside it. Splitting it also lets the bounds buffer live only in the branch that reads it, which drops the zero-length allocation that CFF / CFF2 fonts used to make just to satisfy the shared loop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add vertical glyph advance API to GlyphTypeface Mirror the existing TryGetHorizontalGlyphAdvance / ...Advances pair with vertical equivalents. Until now a vertical-layout caller (CJK, Mongolian) had no advance-only path on GlyphTypeface and had to go through TryGetGlyphMetrics, which after PR2b reads the glyf bounding box per glyph — pure waste when only the advance is needed. VerticalMetricsTable already exposes the per-glyph and batch readers internally (used by TryGetGlyphMetrics(batch)); this is a thin wrapper over them. Tests cover the Latin (no vmtx → false) and CJK (vmtx → positive advances) cases and batch/single parity using Inter and MiSans-Normal. Audit note: HorizontalMetricsTable and VerticalMetricsTable batch readers already span-cache (each fetches _data.Span once per call, reusing a BigEndianBinaryReader across glyphs). No metrics-table refactor is needed — the speculative Part 2 of the plan collapses to nothing. * Expose contiguous glyph indices span on ShapedBuffer Consumers that need a ReadOnlySpan<ushort> of glyph IDs (the upcoming GlyphTypeface.TryGetGlyphBounds batch path, SKFont.GetGlyphWidths, atlas lookups...) previously had to allocate a parallel ushort[] and project GlyphInfo.GlyphIndex into it. Carry that array on the ShapedBuffer instead: - ShapedBuffer rents a parallel ushort[] from ArrayPool alongside the existing GlyphInfo[] rental, exposed as `public ReadOnlySpan<ushort> GlyphIndices`. - The indexer setter syncs both, so HarfBuzz shaping and post-shape mutators (InterWordJustification rewrites the same GlyphIndex) keep the parallel view in lockstep with no caller change. - Split / WithBidiLevel slice the indices alongside the GlyphInfos at the same offsets — both share the parent's pooled arrays. - Dispose returns both rentals. Consumer wiring: - GlyphRunImpl: copies ShapedBuffer.GlyphIndices once via CopyTo when the source is a ShapedBuffer, dropping the per-glyph extract from the position loop. - TextFormatterImpl.CreateEmptyTextLine: switched to the pooled public ctor + indexer (was passing a heap-allocated GlyphInfo[] to the internal slice ctor, which now requires a parallel ushort slice). Tests cover indexer sync, overwrite, ascending split alignment, empty-leading split, and dispose clearing the view. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
2 weeks ago |
|
|
b709c58c6b
|
[Text] Glyph Outline Part 2/13 - GlyphTypeface.GetGlyphOutline implementation (#21406)
* Harden cmap/name/post parsing against malformed fonts
Fonts are untrusted input, but several pre-existing table parsers throw out
of the GlyphTypeface constructor on hostile data, denying the whole font
instead of degrading the affected (cosmetic) table.
- name: wrap NameTable.Load in try/catch so a malformed table falls back to a
default family name (same outcome as an absent name), and bounds-check
NameRecord.GetValue's (offset,length) slice — the record array is validated
at load but each record's storage slice is read later during construction.
- post: wrap PostTable.Load so a malformed cosmetic-hint table degrades to
defaults rather than denying the font.
- cmap format 12/13: clamp the declared length and group count to the buffer,
computing the group span in long to avoid the nGroups*12 int overflow a
hostile count would wrap to a negative slice length.
- cmap format 4 selection: score a Windows Symbol subtable worse than any
Unicode subtable so ASCII resolves regardless of subtable order, while a
Symbol-only font still selects its only subtable.
maxp/cmap remain fatal by design. Behavioural hardening only; public API
unchanged. Backportable independently of the glyph-outline stack.
* Clamp cmap range contents and harden binary reader primitives
Format 12/13 group contents are attacker-controlled: TryGetRange used to
hand the raw uint32 end straight to per-codepoint consumers, so a group
with endCharCode 0x7FFFFFFF turned range enumeration into an unbounded
(for int.MaxValue, non-terminating) loop. Clamp ranges to the Unicode
range and map inverted/out-of-range groups to empty ranges so later
groups still enumerate.
Give the format 4 constructor the same treatment its format 12 sibling
already received: clamp the declared length and segment count to what
the buffer actually holds instead of slicing unchecked (debug asserts
replaced by the clamps).
In BigEndianBinaryReader, bounds-check array reads before allocating
(a hostile length is rejected instead of attempting the allocation),
make EnsureAvailable overflow-proof, and clamp ReadBytes against
negative counts.
* Add font parsing infrastructure for glyph outline/color drawing
Introduces shared utility types that subsequent PRs will use to
implement GetGlyphOutline (glyf table) and GetGlyphDrawing
(COLR v0/v1) on GlyphTypeface:
- ObjectPool<T>: thread-safe object pool used by Decyclers
- Decycler<T> / CycleGuard<T> / DecyclerException: generic
cycle-detection and depth-limiting utility for recursive
font-table traversal (composite glyphs, paint graphs)
- FontVariationSettings: parameter type for the upcoming
GetGlyphOutline / GetGlyphDrawing overloads
- IGlyphDrawing / GlyphDrawingType: return-type contract for color
glyph drawings (outline, color layers, SVG, bitmap)
- CharacterToGlyphMapDictionary: lightweight, allocation-free
IReadOnlyDictionary<int, ushort> view over the cmap, plus
CharacterToGlyphMap.AsReadOnlyDictionary() to expose it
No behavior change; types are not yet consumed in this PR.
* Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Validate ObjectPool maxSize and add unit tests
The ObjectPool<T> constructor previously accepted any maxSize value.
A value of 0 or below silently caused every Return to be discarded,
which is hard to diagnose at the call site.
- Reject maxSize < 1 with ArgumentOutOfRangeException at construction.
- Document the new precondition in the XML comment.
- Add ObjectPoolTests covering: factory null guard, maxSize bounds,
Rent/Return basics, Return ignoring null, max-size enforcement,
validator invocation and rejection, validator-as-reset, plus
concurrent stress tests for cap enforcement and parallel use.
* Validate Decycler maxDepth and add unit tests
The Decycler<T> constructor previously accepted any maxDepth value.
A value of 0 or below made the very first Enter throw
DepthLimitExceeded, which presents as a cycle/depth error at use time
instead of pointing at the construction site.
- Reject maxDepth < 1 with ArgumentOutOfRangeException at construction.
- Document the new precondition in the XML comment.
- Add DecyclerTests covering: maxDepth bounds, Enter/Exit lifecycle,
nested depth, cycle detection, depth-limit-exceeded, depth-vs-cycle
ordering, no state mutation on failed Enter, Reset semantics,
guard idempotency, MaxDepth/CurrentDepth properties, and a struct
type other than int.
* Add tests for CharacterToGlyphMap.AsReadOnlyDictionary
Covers the IReadOnlyDictionary<int, ushort> view returned by
AsReadOnlyDictionary, using the existing Inter font asset:
- ContainsKey agrees with the underlying map for both mapped and
unmapped code points.
- Indexer returns the same glyph id as map.GetGlyph for several
representative ASCII characters.
- Indexer throws KeyNotFoundException for an unmapped code point.
- TryGetValue: positive and negative paths.
- Count is positive and matches the enumerated pair count.
- Enumeration yields (key, value) pairs that round-trip through the
underlying CharacterToGlyphMap.
- Keys enumeration and pair-key enumeration agree.
- Two AsReadOnlyDictionary() calls produce functionally equivalent
views (no identity assumption).
Tests live alongside the existing CharacterToGlyphMap tests in
GlyphTypefaceTests so they can reuse the CustomPlatformTypeface
helper.
* Redesign FontVariationSettings; add GlyphDrawingOptions
FontVariationSettings is changed from a public record to a sealed class
with internal factory methods (FromCoordinates / FromInstance), a
FrozenDictionary backing for NormalizedCoordinates, and structural
Equals/GetHashCode. The type now exclusively models variable-font axis
configuration; palette and bitmap-strike concerns are moved out.
GlyphDrawingOptions is a new public sealed record that carries the
drawing options that are independent of axis configuration: an optional
CPAL palette index (≥ 0) and an optional bitmap-strike pixel size (≥ 1).
Both properties validate at init time and the type participates in
record-equality and with-expressions.
Tests are added for both types (48 new assertions).
* Make FontVariationSettings factories public
FromCoordinates and FromInstance are promoted from internal to public.
They were kept internal while the consuming public API was being designed;
that design is now settled (GlyphTypeface.CreateVariationSettings /
VariationAxes / VariationInstances, planned for PR2).
Class-level remarks are updated to describe the typeface-agnostic design
rationale and point to GlyphTypeface.CreateVariationSettings as the
preferred entry point for user-space axis values.
* Tighten contracts and docs on font-parsing infra
Polish pass on the shared infrastructure types so the contract surface is
unambiguous before PR2 (GetGlyphOutline) and PR3 (GetGlyphDrawing) build
on it:
- IGlyphDrawing now exposes GlyphDrawingType Type so callers can branch
on format without downcasting. The GlyphDrawingType enum was already
defined but unreferenced by the interface; this closes the loop.
PR3's ColorGlyphDrawing and ColorGlyphV1Drawing already implement the
property, so the rebase is a no-op.
- IGlyphDrawing.Bounds and Draw(origin) get explicit coordinate-space
docs (drawing-space, Y-down; origin is the post-flipped glyph anchor).
- Decycler<T> gets a class-level remarks block stating it is not
thread-safe (one instance per traversal) and that Enter throws on
cycle / depth-limit so callers can catch at the outermost site.
- FontVariationSettings.Default documents that null and Default are
interchangeable for parameters typed as FontVariationSettings?.
- ObjectPool.Return documents that callers must not return the same
item twice without an intervening Rent — the pool does not detect
duplicate returns by design.
Tests:
- ObjectPool: validator must not be invoked on Rent (pins the
validate-on-return contract).
- GlyphDrawingOptions: parameterless ctor equals Default (record
equality should make them interchangeable).
- FontVariationSettings: FromCoordinates with both coordinates AND
instanceIndex populated (combined form documented in the API).
83 tests pass (was 76).
* Reshape FontVariationSettings for cache-key use
Switch from a class wrapping FrozenDictionary + nullable instance index
to a readonly struct backed by a sorted ImmutableArray of a dedicated
FontVariationCoordinate record-struct. Driven by the type's role as a
field on FontCollectionKey:
- Hash code is computed once at construction and cached. Lookups in the
font-resolution cache no longer pay an OrderBy allocation per call.
- Equality is a parallel walk over two sorted arrays — no hash lookup,
no TryGetValue per element. Short-circuits on cached-hash mismatch.
- TryGetCoordinate / GetCoordinateOrDefault are linear scans, faster
than hash lookup for the typical handful-of-axes case.
- default(FontVariationSettings) is the "no variation" value. The old
Default singleton goes away; nullable-handling at the cache layer
becomes unnecessary.
- InstanceIndex is dropped from the type. Named-instance selection is
a typeface-level concern that resolves to coordinates; the runtime
settings carry coordinates only, matching CSS / HarfBuzz / DirectWrite
conventions.
Tests rewritten: 34 cases covering struct semantics, sorting,
TryGetCoordinate, hash caching, equality short-circuits, and the
FontVariationCoordinate record's own equality.
* Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Fix auto suggestion
* Add synthetic-font test harness
SyntheticFont / BigEndianBuffer build and mutate in-memory sfnt fonts so the
table parsers can be exercised against hand-crafted malformed input without a
platform shaper. Shared by every parser PR's malformed-font tests.
* Characterize cmap/name/post degradation on malformed input
Regression guards over the synthetic-font harness: a truncated post/name table
degrades to defaults / a fallback family name instead of denying the font, the
cmap format-12 nGroups*12 overflow is clamped, and Format-4 selection prefers a
Unicode subtable over Windows Symbol regardless of directory order.
* Fix dictionary wrapper contract, guard double-exit, and zero-coordinate canonicalization
CharacterToGlyphMapDictionary mixed two membership predicates: Keys and
Count filtered by ContainsGlyph while the indexer, TryGetValue and the
enumerator used TryGetGlyph, so glyph-0 mappings produced keys the
indexer rejected. Everything now answers through TryGetGlyph, and the
Count walk (O(codepoints) over the mapped ranges) is computed once and
cached.
Decycler.Exit decremented the depth unconditionally: CycleGuard is a
copyable ref struct, so a copied guard could exit the same id twice and
grant later traversals extra depth budget. Depth is now only returned
when the id was actually removed from the visited set.
FontVariationSettings.FromCoordinates kept zero-valued coordinates, so
an explicitly-default axis (wght=0 normalized) hashed and compared as a
distinct value from settings omitting the axis - producing duplicate
variation clones and font-collection cache entries downstream. Both
factories now canonicalize zeros away (after the duplicate-axis check,
which the dictionary overload previously skipped entirely).
* Document the cmap dictionary view and tighten Decycler/ObjectPool internals
Add XML docs to CharacterToGlyphMapDictionary's members. Collapse
Decycler.Enter's Contains-then-Add into a single HashSet.Add (a false
return means the id was already visited - a cycle). Make ObjectPool's
lock-free count fast-check a volatile read.
* Simplify FontVariationSettings.Equals to a span SequenceEqual
Map the coordinate comparison onto the inner array via the span overload
(Coordinates normalizes default to Empty, so both spans are valid). The
span SequenceEqual avoids the boxing the LINQ overload would incur on
this dictionary-key type, and FontVariationCoordinate's record-struct
value equality drives the element compare. The cached-hash early-out is
kept.
* Add pre-allocation validation in NameTable.Load so malformed name tables are rejected before creating the names array.
* Make PostTable.Load to catch only the malformed-data exception raised by this parsing path, instead of catching everything.
* Raise ArgumentOutOfRangeException for negative count
* Validate tableLength for CmapFormat12Or13Table ctor
* Fixes GlyphDrawingOptions ArgumentOutOfRangeException nameof usage
* Fix CmapFormat4Table ctor: clamp parallel-array offsets to tableLength
When a malformed subtable declares a length that drives _segCount to 0,
startCodeOffset = endCodeOffset + 0*2 + 2 (reservedPad) can exceed
tableLength, causing Slice() to throw and denying the font entirely.
Apply Math.Min(offset, tableLength) to each derived array offset so that
zero-length slices always start at a valid position, degrading silently
to an empty mapping instead of crashing.
* Revert change
* Only handle specific exceptions in NameTable.Load
Guard against negative count in BigEndianBuffer.Zeros
* Speak user space in the public variation API
Normalized coordinates are font-relative - the same value means different
user positions under different fvar ranges and avar maps - so they cannot
be authored in a style before font resolution and do not interpolate
meaningfully. Every mainstream API (CSS font-variation-settings,
DirectWrite, HarfBuzz, Skia) traffics in user-space values, and a public
normalized type named like theirs invites passing wght=700 into a [-1,1]
slot.
- new public currency: FontVariation (tag=value in designer units) and an
immutable FontVariationSettings with Parse/ToString ("wght=700,wdth=85"),
order-independent structural equality, a cached hash, and CSS last-wins
duplicate handling - usable as a style value and a cache key
- the normalized pair moves out of public view: FontVariationCoordinate
becomes internal NormalizedVariationCoordinate and the normalized
settings struct becomes internal NormalizedVariationPosition, unchanged
in behavior
- the user-space -> normalized conversion stays a per-font, application-
time concern; the fvar/avar reader lands in a follow-up PR
* Accept infinite font variation values
Infinities clamp to the axis range at apply time like any out-of-range
value, so only NaN is rejected now. Parse also uses explicit number
styles instead of NumberStyles.Float since the value text is pre-trimmed
and the whitespace flags were redundant.
* Guard NameRecord.GetValue against decoder exceptions
The selected encodings use replacement fallback and never throw on
malformed bytes, but degrade to an empty value anyway so an
exception-throwing fallback can never deny the font.
* Use nameof(value) in GlyphDrawingOptions setter exceptions
Matches the .NET runtime convention for property setters, also used
elsewhere in this repo (e.g. FormattedText).
* Add GetGlyphOutline API with glyf/loca table parsing
Implements vector outline retrieval for TrueType glyphs:
- LocaTable: parses the 'loca' table (short/long offset variants)
to map glyph IDs to glyf offsets
- GlyfTable: parses the 'glyf' table, supporting simple and
composite glyphs, and builds geometry into an IGeometryContext
- SimpleGlyph / CompositeGlyph / GlyphDescriptor / GlyphComponent /
GlyphFlag / CompositeFlags: data model for the parsed glyph
records
- GlyphDecycler: pooled cycle/depth guard for composite-glyph
recursion (derives from the shared Decycler<int>)
GlyphTypeface now eagerly loads the glyf table when a head table is
present and exposes:
Geometry? GetGlyphOutline(ushort glyphId, Matrix transform,
FontVariationSettings? variation = null)
Returns null when the font has no outline data for the glyph or the
glyph index is out of range.
* Drop variation parameter from GetGlyphOutline
The FontVariationSettings? variation parameter was a forward-compat
placeholder that was never wired through to the glyph parser. Remove it
so the API doesn't advertise capability it doesn't have.
Variable-font support will land as an instance-level concern on
GlyphTypeface itself (mirroring how FontSimulations is already baked in
at construction time), resolved through IFontCollection alongside
FontWeight/Style/Stretch. Adding variation back as a per-call parameter
would be additive at that point if a concrete need emerges.
* Add unit tests for loca/glyf parsing
Covers the glyph-outline parser that GetGlyphOutline builds on, exercised
directly against the Inter test font without a platform render interface:
- LocaTableTests: glyph-count parity with maxp, out-of-range handling,
ascending ranges for every glyph, empty-glyph (space) zero-length range.
- GlyfTableTests: TryGetGlyphData for out-of-range / empty / letter glyphs;
TryBuildGlyphGeometry into a recording IGeometryContext for simple,
empty, out-of-range and composite glyphs; transform application; closed-
figure invariants.
Tables are loaded via their internal factories and geometry is captured
through a fake IGeometryContext, so the parser logic is tested in isolation.
* Add glyph-outline render tests with Inter Variable
Render-comparison coverage for GetGlyphOutline, drawing the returned
Geometry filled in black on a white background and diffing against an
expected PNG (RMSE, 2.2% tolerance, both immediate and compositor paths):
- Should_Render_Inter_Latin_Glyph — Inter-Regular 'A' (simple glyph).
- Should_Render_Inter_Composite_Glyph — Inter-Regular 'Á' (composite
glyph: base + accent), exercises the recursive component path.
- Should_Render_MiSans_CJK_Glyph — MiSans-Normal '中' (CJK ideograph,
many contours / counters).
- Should_Render_InterVariable_At_Default — new Inter Variable asset
rendered at the default variation point. PR2 doesn't apply variation,
so this baselines the default-instance outline against which the
future variable-font work can compare deformed outputs.
- Blank_Variable_Font_Returns_Null_Outline — AdobeBlank2VF (variable
font with intentionally empty glyphs) verifies GetGlyphOutline returns
null without throwing.
Fonts are loaded via SKData.CreateCopy + SKTypeface.FromData so the
typeface's lifetime survives the source stream's disposal. This also
sidesteps a family-name collision: Inter-Regular and InterVariable both
identify as family "Inter", so FontManager resolution would be
ambiguous — direct loading targets each file unambiguously.
InterVariable.ttf is added under Assets/ and picked up by the existing
EmbeddedResource wildcard in both render-test projects.
* Set non-zero fill rule on glyph outlines
Avalonia geometries default to FillRule.EvenOdd. TrueType outlines
expect the non-zero winding rule: where same-orientation contours
overlap (an 'A' crossbar over its diagonal strokes, an accent over its
base glyph in a composite), EvenOdd XORs the regions and leaves visible
gaps. Setting the fill rule once on the outer context at the entry to
TryBuildGlyphGeometry fills the geometry correctly, including through
the composite path's TransformingGeometryContext wrapping (the
wrapping applies to transforms, not to the geometry-level fill rule).
Baselines for the three Inter glyphs were regenerated; the MiSans
ideograph is unaffected because CJK strokes don't overlap.
* Drop per-point debug logging from TransformingGeometryContext
The glyph-outline transform wrapper logged every ArcTo / BeginFigure /
CubicBezierTo / QuadraticBezierTo / LineTo / EndFigure / SetFillRule /
Dispose call through Logger.TryGet(LogEventLevel.Debug, ...). That was
useful while bringing up the glyf parser but runs a guard check per
contour point on every glyph outline build — pure overhead now that the
path is stable. Each method is back to a plain transform-and-delegate;
Dispose is a no-op (the wrapper never owned the inner context).
The exceptional-path warning in TryBuildGlyphGeometry (cyclic composite
glyphs) is unrelated and stays.
* Add InterVariable.ttf to Should_AddGlyphTypeface_By_Stream font list
The glyph-outline render tests embed InterVariable.ttf under
Avalonia.RenderTests/Assets, which the Skia unit-test project picks up
via its `EmbeddedResource Include="..\Avalonia.RenderTests\Assets\**\*.ttf"`
glob. The asset enumeration therefore returns 16 fonts while the test's
hard-coded `infos` list had 15, failing the count assertion.
Add the missing entry in its ordinal-case-insensitive sort position
(after Inter-Regular.ttf). Its production identity — FamilyName
"Inter Variable", Weight Normal (the default fvar instance, usWeightClass
400) — is distinct from the "Inter" family of Inter-Regular/Inter-Bold,
so the (family, weight) round-trip lookup stays unique.
* Fix off-by-one glyph-id bounds check; drop unused usings
GetGlyphOutline rejected out-of-range ids with `glyphId > GlyphCount`,
which let the id equal to GlyphCount slip through — valid glyph ids are
0..GlyphCount-1, and reading at index GlyphCount walks past the end of
the loca offsets. Use `>=` so the upper bound is excluded.
Also remove unused using directives from the glyf parsers
(CompositeGlyph, GlyfTable, GlyphDescriptor, SimpleGlyph).
* Allocate batch glyph-metric buffers only when their source is present
Batch TryGetGlyphMetrics unconditionally sized the hMetrics and vMetrics
temporary buffers to glyphIds.Length even when the font has no hmtx or no
vmtx. Most fonts ship no vmtx, so a large batch heap-allocated a per-glyph
vertical-metric array that was never read.
Size each buffer to zero — a free, empty stackalloc — when its source
table is absent, so it only materialises (and only spills to the heap
past 256 glyphs) when it will actually be filled and read.
* Bail out of composite glyphs that use point matching
A composite component with ARGS_ARE_XY_VALUES clear positions itself by
point matching: arg1/arg2 are point indices, and the component is placed
so one of its points coincides with a point in the already-assembled
parent glyph. CreateComponentTransform only applied a translation when
ARGS_ARE_XY_VALUES was set, so a point-matched component was rendered at
zero translation — a visibly wrong outline.
Point matching isn't implemented. Rather than emit an incorrect glyph,
return false for any composite that uses it (checked before any geometry
is emitted) so the caller falls back to "no outline". XY-value composites
(the overwhelming common case, e.g. accented Latin letters) are
unaffected.
* Support composite glyph point matching
Composite components with ARGS_ARE_XY_VALUES clear are positioned by aligning one of their points onto a point of the already-assembled glyph rather than by an x/y offset. The streaming build path cannot retain points, so route these (rare) composites through a new materialising path: resolve every component into a pooled buffer, apply the point-match translation, then emit the assembled contours.
Out-of-range point indices, phantom-point references, and nested composite components bail out (no outline) rather than render incorrectly. Replaces the previous bail-out, and adds a synthetic-font test covering matched-point alignment and the bail-out cases.
* Add point-matching composite render test
No production font encodes composite point matching (ARGS_ARE_XY_VALUES clear) — verified across the Inter, Noto, Source, SIL (Gentium/Charis/Andika) and Oswald families, which all use x/y offsets. To exercise GlyfTable's point-matching path through the full Skia pipeline, this adds a small purpose-built fixture (PointMatch.ttf, 880 bytes) whose 'P' glyph is a composite: a base rectangle plus a square placed by point matching, aligning the square's bottom-left point onto the rectangle's top-right point.
The baseline shows the square fused to the rectangle's top-right corner; a regression that mishandled point matching would drop it at the origin, which the image diff catches.
* Add missing test font to the list of expected fonts in the Should_AddGlyphTypeface_By_Stream test
* Return an immutable IGeometryImpl from GetGlyphOutline
GetGlyphOutline(ushort, Matrix) returned a mutable StreamGeometry (an AvaloniaObject) with the transform baked in — neither cacheable (every pen position is a distinct geometry) nor safe to share. Reshape to GetGlyphOutline(ushort) returning design-unit-space geometry as an immutable IGeometryImpl (a small sealed wrapper that exposes only the read-only surface and can't be re-opened), so a single instance is safe to cache and share on the future glyph-run hot path. Callers apply scale/position via IGeometryImpl.WithTransform or a drawing-context transform, and draw through the existing DrawGeometry(IGeometryImpl) overload.
* Add SyntheticFont harness self-tests
Round-trip, table patch/replace/remove/truncate, and asset-load tests for the
synthetic-font harness over Inter-Regular and InterVariable.
* Reject non-monotonic contour endpoints in simple glyph parsing
numPoints is derived from the last contour endpoint alone, so a glyph
whose endPtsOfContours array is not strictly increasing sized its point
buffers too small and sent every consumer walk indexing past them - an
IndexOutOfRangeException on each outline build of that glyph. Validate
the endpoints up front and return the default (empty) glyph instead.
* Rename glyph-index parameters to glyphIndex / glyphIndices
Review feedback on the glyph-outline API: the ushort values these members
take are glyph indices, and the platform already speaks that language
(GlyphRun.GlyphIndices), so the parameters say what they are instead of
the looser glyphId/glyphIds. Applies to GetGlyphOutline and the
advance/metrics members this series reworks, plus the tests exercising
them. Purely a naming change - no call site uses named arguments.
* Add failing tests for the off-curve contour walk
The off-curve-start branch of the glyph walker drops one quadratic per
extra point in runs of consecutive off-curve points and ignores an
on-curve last point when picking the figure start. Pins the correct
TrueType decomposition; the on-curve-start case is pinned as-is.
* Unify the contour walkers into one EmitContour
Both geometry emitters carried the same on-curve/off-curve branch pair,
and the off-curve branch had two defects: it advanced past both points
of an off-curve pair (dropping one quadratic per extra point in longer
off-curve runs) and always started at the implied midpoint even when
the last point of the contour is on-curve. One shared walker now does
the TrueType decomposition with a pending-control state machine and an
explicit close, and both the simple-glyph path and the point-matching
composite path route every contour through it.
* Add failing tests for truncated glyf and loca data
The counts in a simple glyph header and in maxp are untrusted: a body
shorter than they promise currently throws out of SimpleGlyph.Create,
and a short loca table reports a glyph count it cannot index.
* Degrade to an empty outline on truncated glyf/loca data
SimpleGlyph.Create bounds-checks the endpoint array, the declared
instruction run and every flag/coordinate read, returning default (and
the rented buffers) instead of throwing when the body is shorter than
its untrusted counts promise. LocaTable clamps its glyph count to the
entries the table data actually covers, replacing an empty validation
block that only claimed to handle short tables.
* Name bit 6 of the simple glyph flags OVERLAP_SIMPLE
The OpenType spec assigns bit 6 (0x40) OVERLAP_SIMPLE; only bit 7 is
reserved.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
|
2 weeks ago |
|
|
72218879d8
|
Fix focus being locked when restoring focus to a control thats detached from visual tree. (#22113)
* add failing test for detached focus * Clear focus if restore element is not in focus scope * check for focus eligibility when restoring focus * add failing test for second focus scope stealing focus * if focus scope is not the current focus scope, don't attempt to set focus |
2 weeks ago |
|
|
2e7d2c5c60
|
Fix infinite loop when a text run shapes to no glyphs (#22119)
* Add failing tests for runs that shape to no glyphs A shaper hides the default ignorables it substitutes for line breaks behind the font's space glyph, and deletes them when the font has no such glyph. A run holding nothing but a line break then shapes to an empty glyph buffer while still owning its characters. - TextFormatter drops that run today, so the line covers no text and the layout loop never advances past it - measuring a wrapping TextBlock whose text starts with a newline never returns. - GlyphRun indexes its glyph list without checking it is non-empty, so hit-testing such a run throws IndexOutOfRangeException. Covers all three layers: GlyphRun hit-testing, the formatted line, and the TextLayout repro from the issue. The layout test bounds maxLines so a regression fails instead of hanging the test run. The Skia tests embed the headless platform's BareMinimum.ttf, which has four glyphs and no space, rather than a copy of it. * Keep text runs that shape to no glyphs ShapeTogether split the shaped buffer by glyph count, so a run whose glyphs were all deleted by the shaper was skipped and its characters rolled into previousLength for a following run to absorb. When no such run follows, the characters are lost: the line reports a length of 0 and TextLayout formats the same line forever. Splitting by text length preserves the case the accumulation exists for - a run whose glyphs merged into a neighbouring cluster splits off no text either - and stops discarding characters that shaped to nothing. That makes zero-glyph glyph runs reachable for the first time, so: - GetDistanceFromCharacterHit, FindGlyphIndex and FindNearestCharacterHit handle an empty glyph list. There is no cluster to snap to and the run sits at a single position, so it degenerates to one zero-width cluster. - InkBounds answers empty directly instead of building a platform glyph run. TextLineImpl reads it for every shaped run in a line, and the Skia implementation creates an SKFont and measures glyph widths in its constructor - wasted on a run that marks nothing. Fixes #22004 * Adjust GlyphRun.InkBounds xml comment |
2 weeks ago |
|
|
31d6979377
|
Fix data validation errors not showing for OneWayToSource bindings (#22103)
* Add failing tests for OneWayToSource validation (#8235) Data validation errors from validation attributes (e.g. [MaxLength]) and INotifyDataErrorInfo are not displayed when binding with Mode=OneWayToSource. Add tests covering both the DataAnnotations and INDEI cases when writing to the source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwdaykrFyoMZFeVmWMydb * Publish data validation errors for OneWayToSource bindings (#8235) In OneWayToSource mode, BindingExpression.OnNodeValueChanged discarded any data validation error produced when writing the value to the source, so validation attributes and INotifyDataErrorInfo errors were never displayed. Publish (and clear) the error via UnchangedValue so that the error state reaches the target without pushing a value back to it, preserving the one-way-to-source semantics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwdaykrFyoMZFeVmWMydb * Added passing test for #15378. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
3 weeks ago |
|
|
7527557ca0
|
Short-circuit the binding chain on a null-conditional operator (#22082)
* Add failing test for issue described in #22069. https://github.com/AvaloniaUI/Avalonia/pull/22069#issuecomment-5442287978 * Add failing test for #18949. * Add failing tests for null conditional on attached property. * Short-circuit the binding chain on a null-conditional operator. The null-conditional operator in a binding path was only applied to the node it was attached to: a null source produced a null value which was then passed to the next node in the chain, which raised "Value is null.". C# instead short-circuits the remainder of the expression, so `a?.b.c` evaluates to null when `a` is null. Do the same for binding paths. When a null-conditional node has a null source it now sets its own value and that of all subsequent nodes to null, and the binding publishes null rather than an error. Publishing null rather than UnsetValue means TargetNullValue still applies. Attached properties in reflection bindings never honoured the operator at all: the grammar parses `?.(Foo.Bar)` and sets AttachedPropertyNameNode.AcceptsNull, but ExpressionNodeFactory discarded the flag and AvaloniaPropertyAccessorNode had no way to accept it. Pass it through. Compiled bindings were unaffected as they route attached properties through PropertyAccessorNode. Fixes #18949. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Atuuu4jtp14QXXoCzkp2A6 * Add TargetNullValue tests for short-circuited chains. Covers `A?.B.C` where A is null, for both CLR and Avalonia properties. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aahFHMmgxZtZ5EH3H5Xcc --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
3 weeks ago |
|
|
eeb9e36a05
|
[Text] Glyph Outline Part 1/13 - Utility types for glyph outline support (#21405)
* Harden cmap/name/post parsing against malformed fonts
Fonts are untrusted input, but several pre-existing table parsers throw out
of the GlyphTypeface constructor on hostile data, denying the whole font
instead of degrading the affected (cosmetic) table.
- name: wrap NameTable.Load in try/catch so a malformed table falls back to a
default family name (same outcome as an absent name), and bounds-check
NameRecord.GetValue's (offset,length) slice — the record array is validated
at load but each record's storage slice is read later during construction.
- post: wrap PostTable.Load so a malformed cosmetic-hint table degrades to
defaults rather than denying the font.
- cmap format 12/13: clamp the declared length and group count to the buffer,
computing the group span in long to avoid the nGroups*12 int overflow a
hostile count would wrap to a negative slice length.
- cmap format 4 selection: score a Windows Symbol subtable worse than any
Unicode subtable so ASCII resolves regardless of subtable order, while a
Symbol-only font still selects its only subtable.
maxp/cmap remain fatal by design. Behavioural hardening only; public API
unchanged. Backportable independently of the glyph-outline stack.
* Clamp cmap range contents and harden binary reader primitives
Format 12/13 group contents are attacker-controlled: TryGetRange used to
hand the raw uint32 end straight to per-codepoint consumers, so a group
with endCharCode 0x7FFFFFFF turned range enumeration into an unbounded
(for int.MaxValue, non-terminating) loop. Clamp ranges to the Unicode
range and map inverted/out-of-range groups to empty ranges so later
groups still enumerate.
Give the format 4 constructor the same treatment its format 12 sibling
already received: clamp the declared length and segment count to what
the buffer actually holds instead of slicing unchecked (debug asserts
replaced by the clamps).
In BigEndianBinaryReader, bounds-check array reads before allocating
(a hostile length is rejected instead of attempting the allocation),
make EnsureAvailable overflow-proof, and clamp ReadBytes against
negative counts.
* Add font parsing infrastructure for glyph outline/color drawing
Introduces shared utility types that subsequent PRs will use to
implement GetGlyphOutline (glyf table) and GetGlyphDrawing
(COLR v0/v1) on GlyphTypeface:
- ObjectPool<T>: thread-safe object pool used by Decyclers
- Decycler<T> / CycleGuard<T> / DecyclerException: generic
cycle-detection and depth-limiting utility for recursive
font-table traversal (composite glyphs, paint graphs)
- FontVariationSettings: parameter type for the upcoming
GetGlyphOutline / GetGlyphDrawing overloads
- IGlyphDrawing / GlyphDrawingType: return-type contract for color
glyph drawings (outline, color layers, SVG, bitmap)
- CharacterToGlyphMapDictionary: lightweight, allocation-free
IReadOnlyDictionary<int, ushort> view over the cmap, plus
CharacterToGlyphMap.AsReadOnlyDictionary() to expose it
No behavior change; types are not yet consumed in this PR.
* Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Validate ObjectPool maxSize and add unit tests
The ObjectPool<T> constructor previously accepted any maxSize value.
A value of 0 or below silently caused every Return to be discarded,
which is hard to diagnose at the call site.
- Reject maxSize < 1 with ArgumentOutOfRangeException at construction.
- Document the new precondition in the XML comment.
- Add ObjectPoolTests covering: factory null guard, maxSize bounds,
Rent/Return basics, Return ignoring null, max-size enforcement,
validator invocation and rejection, validator-as-reset, plus
concurrent stress tests for cap enforcement and parallel use.
* Validate Decycler maxDepth and add unit tests
The Decycler<T> constructor previously accepted any maxDepth value.
A value of 0 or below made the very first Enter throw
DepthLimitExceeded, which presents as a cycle/depth error at use time
instead of pointing at the construction site.
- Reject maxDepth < 1 with ArgumentOutOfRangeException at construction.
- Document the new precondition in the XML comment.
- Add DecyclerTests covering: maxDepth bounds, Enter/Exit lifecycle,
nested depth, cycle detection, depth-limit-exceeded, depth-vs-cycle
ordering, no state mutation on failed Enter, Reset semantics,
guard idempotency, MaxDepth/CurrentDepth properties, and a struct
type other than int.
* Add tests for CharacterToGlyphMap.AsReadOnlyDictionary
Covers the IReadOnlyDictionary<int, ushort> view returned by
AsReadOnlyDictionary, using the existing Inter font asset:
- ContainsKey agrees with the underlying map for both mapped and
unmapped code points.
- Indexer returns the same glyph id as map.GetGlyph for several
representative ASCII characters.
- Indexer throws KeyNotFoundException for an unmapped code point.
- TryGetValue: positive and negative paths.
- Count is positive and matches the enumerated pair count.
- Enumeration yields (key, value) pairs that round-trip through the
underlying CharacterToGlyphMap.
- Keys enumeration and pair-key enumeration agree.
- Two AsReadOnlyDictionary() calls produce functionally equivalent
views (no identity assumption).
Tests live alongside the existing CharacterToGlyphMap tests in
GlyphTypefaceTests so they can reuse the CustomPlatformTypeface
helper.
* Redesign FontVariationSettings; add GlyphDrawingOptions
FontVariationSettings is changed from a public record to a sealed class
with internal factory methods (FromCoordinates / FromInstance), a
FrozenDictionary backing for NormalizedCoordinates, and structural
Equals/GetHashCode. The type now exclusively models variable-font axis
configuration; palette and bitmap-strike concerns are moved out.
GlyphDrawingOptions is a new public sealed record that carries the
drawing options that are independent of axis configuration: an optional
CPAL palette index (≥ 0) and an optional bitmap-strike pixel size (≥ 1).
Both properties validate at init time and the type participates in
record-equality and with-expressions.
Tests are added for both types (48 new assertions).
* Make FontVariationSettings factories public
FromCoordinates and FromInstance are promoted from internal to public.
They were kept internal while the consuming public API was being designed;
that design is now settled (GlyphTypeface.CreateVariationSettings /
VariationAxes / VariationInstances, planned for PR2).
Class-level remarks are updated to describe the typeface-agnostic design
rationale and point to GlyphTypeface.CreateVariationSettings as the
preferred entry point for user-space axis values.
* Tighten contracts and docs on font-parsing infra
Polish pass on the shared infrastructure types so the contract surface is
unambiguous before PR2 (GetGlyphOutline) and PR3 (GetGlyphDrawing) build
on it:
- IGlyphDrawing now exposes GlyphDrawingType Type so callers can branch
on format without downcasting. The GlyphDrawingType enum was already
defined but unreferenced by the interface; this closes the loop.
PR3's ColorGlyphDrawing and ColorGlyphV1Drawing already implement the
property, so the rebase is a no-op.
- IGlyphDrawing.Bounds and Draw(origin) get explicit coordinate-space
docs (drawing-space, Y-down; origin is the post-flipped glyph anchor).
- Decycler<T> gets a class-level remarks block stating it is not
thread-safe (one instance per traversal) and that Enter throws on
cycle / depth-limit so callers can catch at the outermost site.
- FontVariationSettings.Default documents that null and Default are
interchangeable for parameters typed as FontVariationSettings?.
- ObjectPool.Return documents that callers must not return the same
item twice without an intervening Rent — the pool does not detect
duplicate returns by design.
Tests:
- ObjectPool: validator must not be invoked on Rent (pins the
validate-on-return contract).
- GlyphDrawingOptions: parameterless ctor equals Default (record
equality should make them interchangeable).
- FontVariationSettings: FromCoordinates with both coordinates AND
instanceIndex populated (combined form documented in the API).
83 tests pass (was 76).
* Reshape FontVariationSettings for cache-key use
Switch from a class wrapping FrozenDictionary + nullable instance index
to a readonly struct backed by a sorted ImmutableArray of a dedicated
FontVariationCoordinate record-struct. Driven by the type's role as a
field on FontCollectionKey:
- Hash code is computed once at construction and cached. Lookups in the
font-resolution cache no longer pay an OrderBy allocation per call.
- Equality is a parallel walk over two sorted arrays — no hash lookup,
no TryGetValue per element. Short-circuits on cached-hash mismatch.
- TryGetCoordinate / GetCoordinateOrDefault are linear scans, faster
than hash lookup for the typical handful-of-axes case.
- default(FontVariationSettings) is the "no variation" value. The old
Default singleton goes away; nullable-handling at the cache layer
becomes unnecessary.
- InstanceIndex is dropped from the type. Named-instance selection is
a typeface-level concern that resolves to coordinates; the runtime
settings carry coordinates only, matching CSS / HarfBuzz / DirectWrite
conventions.
Tests rewritten: 34 cases covering struct semantics, sorting,
TryGetCoordinate, hash caching, equality short-circuits, and the
FontVariationCoordinate record's own equality.
* Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Fix auto suggestion
* Add synthetic-font test harness
SyntheticFont / BigEndianBuffer build and mutate in-memory sfnt fonts so the
table parsers can be exercised against hand-crafted malformed input without a
platform shaper. Shared by every parser PR's malformed-font tests.
* Characterize cmap/name/post degradation on malformed input
Regression guards over the synthetic-font harness: a truncated post/name table
degrades to defaults / a fallback family name instead of denying the font, the
cmap format-12 nGroups*12 overflow is clamped, and Format-4 selection prefers a
Unicode subtable over Windows Symbol regardless of directory order.
* Fix dictionary wrapper contract, guard double-exit, and zero-coordinate canonicalization
CharacterToGlyphMapDictionary mixed two membership predicates: Keys and
Count filtered by ContainsGlyph while the indexer, TryGetValue and the
enumerator used TryGetGlyph, so glyph-0 mappings produced keys the
indexer rejected. Everything now answers through TryGetGlyph, and the
Count walk (O(codepoints) over the mapped ranges) is computed once and
cached.
Decycler.Exit decremented the depth unconditionally: CycleGuard is a
copyable ref struct, so a copied guard could exit the same id twice and
grant later traversals extra depth budget. Depth is now only returned
when the id was actually removed from the visited set.
FontVariationSettings.FromCoordinates kept zero-valued coordinates, so
an explicitly-default axis (wght=0 normalized) hashed and compared as a
distinct value from settings omitting the axis - producing duplicate
variation clones and font-collection cache entries downstream. Both
factories now canonicalize zeros away (after the duplicate-axis check,
which the dictionary overload previously skipped entirely).
* Document the cmap dictionary view and tighten Decycler/ObjectPool internals
Add XML docs to CharacterToGlyphMapDictionary's members. Collapse
Decycler.Enter's Contains-then-Add into a single HashSet.Add (a false
return means the id was already visited - a cycle). Make ObjectPool's
lock-free count fast-check a volatile read.
* Simplify FontVariationSettings.Equals to a span SequenceEqual
Map the coordinate comparison onto the inner array via the span overload
(Coordinates normalizes default to Empty, so both spans are valid). The
span SequenceEqual avoids the boxing the LINQ overload would incur on
this dictionary-key type, and FontVariationCoordinate's record-struct
value equality drives the element compare. The cached-hash early-out is
kept.
* Add pre-allocation validation in NameTable.Load so malformed name tables are rejected before creating the names array.
* Make PostTable.Load to catch only the malformed-data exception raised by this parsing path, instead of catching everything.
* Raise ArgumentOutOfRangeException for negative count
* Validate tableLength for CmapFormat12Or13Table ctor
* Fixes GlyphDrawingOptions ArgumentOutOfRangeException nameof usage
* Fix CmapFormat4Table ctor: clamp parallel-array offsets to tableLength
When a malformed subtable declares a length that drives _segCount to 0,
startCodeOffset = endCodeOffset + 0*2 + 2 (reservedPad) can exceed
tableLength, causing Slice() to throw and denying the font entirely.
Apply Math.Min(offset, tableLength) to each derived array offset so that
zero-length slices always start at a valid position, degrading silently
to an empty mapping instead of crashing.
* Revert change
* Only handle specific exceptions in NameTable.Load
Guard against negative count in BigEndianBuffer.Zeros
* Speak user space in the public variation API
Normalized coordinates are font-relative - the same value means different
user positions under different fvar ranges and avar maps - so they cannot
be authored in a style before font resolution and do not interpolate
meaningfully. Every mainstream API (CSS font-variation-settings,
DirectWrite, HarfBuzz, Skia) traffics in user-space values, and a public
normalized type named like theirs invites passing wght=700 into a [-1,1]
slot.
- new public currency: FontVariation (tag=value in designer units) and an
immutable FontVariationSettings with Parse/ToString ("wght=700,wdth=85"),
order-independent structural equality, a cached hash, and CSS last-wins
duplicate handling - usable as a style value and a cache key
- the normalized pair moves out of public view: FontVariationCoordinate
becomes internal NormalizedVariationCoordinate and the normalized
settings struct becomes internal NormalizedVariationPosition, unchanged
in behavior
- the user-space -> normalized conversion stays a per-font, application-
time concern; the fvar/avar reader lands in a follow-up PR
* Accept infinite font variation values
Infinities clamp to the axis range at apply time like any out-of-range
value, so only NaN is rejected now. Parse also uses explicit number
styles instead of NumberStyles.Float since the value text is pre-trimmed
and the whitespace flags were redundant.
* Guard NameRecord.GetValue against decoder exceptions
The selected encodings use replacement fallback and never throw on
malformed bytes, but degrade to an empty value anyway so an
exception-throwing fallback can never deny the font.
* Use nameof(value) in GlyphDrawingOptions setter exceptions
Matches the .NET runtime convention for property setters, also used
elsewhere in this repo (e.g. FormattedText).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
|
3 weeks ago |
|
|
3b259812c4
|
Fixed dispatcher frame capturing wrong dispatcher (#22086)
|
3 weeks ago |
|
|
73ab31fcce
|
Use _effective_ capturer (which can be recognizer) for PlatformCapture (#22076)
|
3 weeks ago |
|
|
4142052f9e
|
Add BringIntoView pass to the LayoutManager (#22002)
* Add BringIntoView pass to the LayoutManager * Make ProcessBringIntoViewRequests part of the standard layout pass * Clarify why TryScrollIntoViewNow's result is ignored --------- Co-authored-by: grokys <grokys@users.noreply.github.com> |
3 weeks ago |
|
|
15a9c99fc6
|
Add typed binding expressions (#21552)
* Update ncrunch config.
* Initial groundwork for typed binding expressions.
- Moved a bunch of stuff from `UntypedBindingExpressionBase` to `BindingExpressionBase`
- Make various APIs accept `BindingExpressionBase` instead of `UntypedBindingExpressionBase`
- Added a typed `IPropertyInfo`
- Added a method on the `CompiledBindingPathBuilder` to build typed property accessors
- Initial basic implementation of `TypedBindingExpression`
* Track values in typed binding expression.
* Support binding mode in typed binding expression.
* Add typed binding expression benchmarks.
Add Setup/Values benchmarks comparing the typed binding expression
against the untyped CompiledBinding (as emitted by the XAML compiler
today) and the reflection-based Binding.
Writing the benchmarks surfaced that TypedBindingExpression never
detached: it had no Dispose override, so disposing a binding (or
rebinding the same property) leaked its PropertyChanged subscriptions
and left it registered in the value store. Wire up disposal mirroring
UntypedBindingExpressionBase: stop, detach handlers, remove from the
value store and frame. This required widening
IBindingExpressionSink.OnCompleted from UntypedBindingExpressionBase to
BindingExpressionBase. Also fix a nullable warning that broke the
Release build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
* Don't box value in IBindingExpressionSink.OnChanged.
Instead notify the sink of what's changed and let the sink read the value boxed or unboxed.
* Move `IValueEntry` to `BindingExpressionBase`
* Fall back to BindingExpression.
Make `TypedPropertyElement` derive from `PropertyElement` and fall back to creating a standard boxing `BindingExpression` if any of the requirements for a typed binding expression are not met.
* Don't use typed expressions for DataContext.
* Emit typed binding expression from XAML compiler.
When a compiled binding path is shape-eligible (single CLR property on a
reference-type source, no transforms, instance getter) the compiler now
emits a call to the typed CompiledBindingPathBuilder.Property<TSource,
TResult> overload, producing a TypedPropertyElement that the runtime
turns into a non-boxing TypedBindingExpression<TSource, TValue>. Other
shapes continue to use the existing untyped emission path, and runtime
fallback to BindingExpression still kicks in when modifiers (Source,
Converter, StringFormat, etc.) make the typed expression unsuitable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add failing tests for TwoWay typed binding source echo.
TypedBindingExpression writes the source value back to the source both on
attach and whenever the source raises a change: pushing the value to the
target re-enters OnTargetPropertyChanged, which (in TwoWay mode) calls
WriteValueToSource with the value that just arrived from the source.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Don't echo source value back to source in TwoWay typed binding.
When TypedBindingExpression pushed the source value to the target, the
resulting target PropertyChanged re-entered OnTargetPropertyChanged which,
in TwoWay mode, wrote the value straight back to the source - a redundant
round-trip on every attach and every source-originated change.
Guard the source->target push with a flag and skip WriteValueToSource while
it is set, so only genuine target changes are written back to the source.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Address typed binding code-review follow-ups.
- Reset _isRunning when a typed binding is unsubscribed so the expression
can be restarted (and re-subscribe to its source) if the value store
reactivates the entry later, matching UntypedBindingExpressionBase.Stop().
- Remove a stray `using static PropertySetSnapshot` import.
- Extract the duplicated IValueEntry value-unwrapping logic (shared by
EffectiveValue<T> and DirectPropertyBase) into IValueEntry.TryGetValue.
- Drop the unreachable UpdateSourceTrigger NotSupportedException in
CreateTypedExpression; CanUseTypedBindingExpression already constrains it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix TypedBinding_Values benchmark build error.
The typed binding path was built with a single-argument `Property(propertyInfo)`
call, which has no matching overload, so the benchmark project did not compile.
Use the same typed three-argument overload as TypedBinding_Setup so the benchmark
exercises the TypedPropertyElement path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Skip typed binding expression for data-validation properties.
TypedBindingExpression does not support data validation, but the eligibility
check didn't account for it, so a directly-assignable single-property DataContext
binding to a validation-enabled target (e.g. TextBox.Text, NumericUpDown.Value)
would take the typed path and silently drop validation errors.
Fall back to the untyped BindingExpression when the target property enables data
validation. Data validation support in the typed expression can be added as a
follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Clarify that data validation is not supported.
* Address typed binding review comments.
- React to null/empty PropertyChanged.PropertyName ("all properties
changed") in the typed expression, matching the untyped path.
- Swallow source getter exceptions raised during PropertyChanged.
- Fall back to the untyped path for non-StyledElement targets, read-only
sources and wider target types in TwoWay/OneWayToSource modes.
- Fix a stray space in an exception message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Share TypedBindingExpression.Attach validation across instantiations.
Factor the validation logic (most notably the exception string
formatting) out of the generic Attach method into a non-generic static
helper. It only uses typeof(TValue), not TValue, so sharing it avoids
duplicating the code per generic instantiation, a meaningful NativeAOT
size saving (~3.3 KB => ~2.5 KB per instantiation).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Update API suppressions.
These APIs are in a `[PrivateApi]`.
* Use cached boolean boxes in typed binding expression.
Merging main brought in the cached boxed booleans emitted for compiled
binding property getters (#21065), but bindings that now take the typed
binding expression path don't go through that getter: the value is boxed
in TypedBindingExpression.GetUntypedValue when the target property isn't
strongly typed (e.g. binding a bool to TextBlock.Tag). Box booleans via a
shared cache there too, restoring the no-allocation-per-read behaviour.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxawATDHa6rbPaDmPCLHZ
* Extract the whole TypedBindingExpression.Attach body into AttachCore.
|
3 weeks ago |
|
|
b1e68c3e0f
|
Implement ObjectMultiConverters. (#21428)
* Implement object multi converters and tests. * Rename null check methods * Remove method AreNotEqual * Move to ObjectConverters * Change logic for AreAnyNull --------- Co-authored-by: Emmanuel Hansen <emmausssss@gmail.com> |
3 weeks ago |
|
|
ea2dc8fef7
|
Fix ServerCompositionDrawingSurface orphaning GPU snapshots when an update is processed after Dispose (#21876)
* Add failing test: CompositionDrawingSurface update processed after Dispose orphans the GPU snapshot A commit batch is processed on the render thread in serialization order: the dispose list is written before queued server jobs. The legal user-code order `surface.UpdateAsync(image); surface.Dispose();` therefore executes on the render thread as Dispose() -> UpdateWithAutomaticSync(), and the update stores a fresh snapshot ref into the already-disposed ServerCompositionDrawingSurface. Nothing disposes that ref afterwards, so the GPU-backed snapshot is cleaned up by the RefCountable.Ref<T> critical finalizer, which performs GPU work on the finalizer thread and races the compositor render loop (#21865). * Fix ServerCompositionDrawingSurface orphaning GPU snapshots when an update is processed after Dispose Add a disposed flag: an Update processed after Dispose now disposes the fresh snapshot immediately on the render thread (where the GPU context is current) instead of storing it into the disposed surface where nothing will ever release it. This removes the finalizer-thread GPU cleanup path that races the compositor render loop and crashes in sk_canvas_flush (#21865). |
3 weeks ago |
|
|
a83222ea6a
|
[Text] Ignore default ignorable codepoints in font fallback (#22059)
* Add Emoji, Emoji_Presentation and Default_Ignorable Unicode data Font fallback has to tell content codepoints apart from ones a font is not expected to draw, and emoji presentation cannot be decided from the general category alone. None of that data was available. - Pack Emoji, Emoji_Presentation and Default_Ignorable_Code_Point as single bits into the spare bits of the GraphemeBreak trie word (it only used 7 of 32); the emoji properties come from the emoji-data.txt the generator already reads for Extended_Pictographic. - Expose them as Codepoint.IsEmoji, HasEmojiPresentation and IsDefaultIgnorable. - Regenerate GraphemeBreak.trie.cs; no other generated file changes. * Add failing test for default ignorables in cluster coverage A cluster of base + U+FE0F + combining mark is handed to the primary font even though it has no glyph for the mark, because every candidate font is required to cover the variation selector as well and none does. The mark renders as .notdef. The fallback font is Noto Sans rather than DejaVu Sans: DejaVu maps U+FE0F and would hide the defect. * Ignore default ignorable codepoints when matching cluster coverage Variation selectors are nonspacing marks by general category, so the cluster coverage check demanded a glyph for them from every candidate font. Text fonts do not map U+FE0F, which made any base + U+FE0F + mark cluster look unmatchable: the fallback search was keyed on the variation selector, found nothing, and the cluster fell back to the primary font with the mark rendered as .notdef. This is what made emoji keycap sequences render as a digit followed by a tofu box. - Skip default ignorables (along with the break/control/format codepoints already handled) when testing cluster coverage and when picking the codepoint the fallback search is keyed on. - A cluster holding only a default ignorable no longer ends a shapeable run; it renders nothing whichever font it lands on. * Unify glyph-demand predicate in cluster coverage Default_Ignorable_Code_Point already covers every invisible format codepoint, so the blanket Format exclusion in NeedsGlyph only skipped the deliberately visible ones (prepended concatenation marks like U+0600, interlinear annotation chars) - those should demand a glyph, and the base-only pass already did. Dropping Format makes NeedsGlyph identical to the run-ending condition in TryGetShapeableLength, which now calls it instead of restating it. |
3 weeks ago |
|
|
a9cd0d1402
|
fix(animation): keep transform playback in sync when hidden (#21896)
OnlyIfVisible paused properties applied directly to a Visual, but transform setters continued advancing because their AnimationInstance targeted a child Transform. This left scale and opacity out of phase after visibility was restored.\n\nCarry the owning visual separately from the property target so transform instances observe the same visibility and detachment lifecycle. Cover the pause and resume timeline with a regression test. Co-authored-by: Julien Lebosquain <julien@lebosquain.net> |
4 weeks ago |
|
|
79162b5da8
|
feat: implement unified IFormattable on Color, HslColor, and HsvColor (#20919)
* fix: correct HslColor.ToString() prefix from hsva to hsla
Pre-existing copy-paste bug: HslColor.ToString() was outputting
"hsva(" instead of "hsla(" for its default format.
* feat: implement unified IFormattable on Color, HslColor, and HsvColor
All three color types now support all format specifiers via
auto-conversion, following the DateTime analogy where the same
format codes work regardless of source type.
Format specifiers:
Hex: X (#AARRGGBB), x (#RRGGBB), H (#RRGGBBAA)
RGB: R/r (absolute), R%/r% (percent)
HSL: L/l (CSS standard), L%/l% (all percent)
HSV: V/v (CSS standard), V%/v% (all percent)
Convention: uppercase = include alpha (rgba/hsla/hsva prefix),
lowercase = exclude alpha (rgb/hsl/hsv prefix).
Each type handles its native model natively and delegates
cross-model formats via ToRgb()/ToHsl()/ToHsv().
Breaking changes from prior PR iteration:
- "h" dropped (identical to "x" without alpha)
- "C"/"c" removed, reserved for future complex format strings
- "P"/"p" replaced by "R%"/"r%"
- "R" now outputs rgba() not rgb() (CSS convention)
- "L" now outputs hsla() not hsl() (CSS convention)
- "V" now outputs hsva() not hsv() (CSS convention)
* refactor(media): clarify color CSS formatters
Color formatting now exposes the same IFormattable implementation in the BuildTask compile path as in normal builds. Keeping the interface conditional made the public contract harder to reason about even though the formatting members are System-only APIs.
Remove the BuildTask guard from the formatting members, combine alpha and no-alpha CSS helpers behind includeAlpha parameters, and rename the helpers so future changes preserve the CSS-compliant output contract.
* Remove regions
---------
Co-authored-by: Jumar Macato <16554748+jmacato@users.noreply.github.com>
Co-authored-by: Nathan Nguyen <HoangAnhVu.Nguyen-1@student.uts.edu.au>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
|
4 weeks ago |
|
|
055e123b5c
|
Call ApplyStyling unconditionally in MeasureCore (#21572)
* Add unit test for styling affecting measurements in WindowDrawnDecorationsContent * Refactor layout measurement to apply styling before visibility checks * Add core measure test * Add StackPanel test * Call ApplyStyling unconditionally in MeasureCore --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net> |
4 weeks ago |
|
|
fa122d7735
|
Implement visual geometry hit testing (#21768)
* Implement visual geometry hit testing * fix xml comment * fix xml comment * update api diff * Introduced ICompositionHitTester to avoid duplicated hit test code between point and geometry * Add geometry hit testing page to RenderDemo * fix geometry hit testing not including stroke * fix test * update api and tests * update api diff * Update GeometryHitTestingPage with new API * addressed reviews. * remove nullability in GeometryHitTestResult Visual hit --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net> |
1 month ago |
|
|
92ea5b7a7d
|
fix(input): fix AccessKeyHandler when no descendant control has focus (#21920)
* fix(input): fix AccessKeyHandler when no descendant control has focus - Update IsFocusWithinOwner to use routed event's Source instead of re-querying KeyboardDevice.Instance.FocusedElement - Allow access keys (Alt/mnemonics) to work immediately after Window opens when FocusedElement is null or owner itself - Update shared test helpers in AccessKeyHandlerTests to populate event Source Fixes #21806 * fix(input): address review feedback on AccessKeyHandler focus fix - Type IsFocusWithinOwner's owner parameter as InputElement (matching _owner) and drop the now-redundant `is Visual` check - Fix indentation in IsFocusWithinOwner - Add Should_Raise_AccessKey_When_Focus_Is_On_Descendant, covering the IsVisualAncestorOf branch by raising KeyDown/KeyUp on a descendant control instead of the owner - Revert the no-op Source assignment in the KeyDown/KeyUp test helpers - Shorten the comment in Should_Raise_Key_Events_For_Registered_Access_Key --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net> |
1 month ago |
|
|
064b84a982
|
Preserve current `Animation` progress if `SpeedRatio` or `PlaybackDirection` changes (#19830)
* Add AnimationSpeedPage to RenderDemo * Add tests * Implement fix * Minor improvements Remove leftover vars/params Replace some `if`s with terniary assignment Improve comments Unduplicate `playbackReversed` code * Add unit test DelayBetweenIterations_Behind_Initial_Point_Is_In_Front_Of_Iterations * Add animation time precision * Add missing check for negative `DelayBetweenIterations` * Fix zero duration regression --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net> |
2 months ago |
|
|
bdb0738dba
|
Implement a copy-on-write list for VisualChildren/LogicalChildren (#21884)
* Implement copy-on-write list for Visual/LogicalChildren * Ensure that adding/removing children is valid OnAttached/OnDetached |
2 months ago |
|
|
1bd786090d
|
CompositionBrush corrections (#21873)
* Add failing tests for composition gradient brush change tracking Three defects in the unreleased CompositionBrush surface: - Replacing GradientStops after the first commit never reaches the server: the hand-written property registers nothing for serialization, so the change only ships once an unrelated tracked property dirties the brush. - SpreadMethod has the same gap. - A mutable Media.GradientStop crosses the batch by reference and the render thread then reads a UI-thread object at replay time. - A CompositionBrush resolves its server object for any compositor, so a foreign compositor ends up sharing a resource across render loops. * Track composition gradient brush changes and respect compositor affinity - GradientStops and SpreadMethod now register for serialization when assigned, so changes made after the first commit reach the server without waiting for an unrelated tracked property to dirty the brush. In-place list mutation stays untracked and is documented as requiring re-assignment. - Non-composition gradient stops are snapshotted to ImmutableGradientStop at serialization time instead of crossing the batch by reference, since the render thread reads the server list at replay time. - Resolving a CompositionBrush for a different compositor now throws instead of silently wiring one server resource into two render loops. Transient contexts without a compositor keep receiving the client brush unchanged. |
2 months ago |
|
|
b2d9e7904b
|
fix(focus): infinite loop in tab stop search with TabNavigation=Once (#21864)
* fix(focus): infinite loop in tab stop search with TabNavigation=Once
`FocusManager.FindNextElement(Next|Previous)` and `TryMoveFocus(Next|Previous)` never
return when the focused element sits inside a container with
`KeyboardNavigationMode.Once`. The calling thread spins at 100% CPU forever; in a
desktop app that means a hard hang of the UI thread requiring the process to be killed.
## Root cause
The upward walk in `GetNextTabStop` / `GetPreviousTabStop` advances at the end of each
iteration with `parent = GetFocusParent(parent)`. But when the walk reaches a container
whose `TabNavigation` is `Once` (or `None`, in one branch), the code resets `parent`
from `focused` instead of from `current`:
```csharp
current = parent;
parent = FocusHelpers.GetFocusParent(focused); // focused is a loop invariant
```
`focused` never changes, so `parent` drops back down to the focused element's immediate
parent. The next iteration walks up to the same container again and takes the same
branch, so the walk oscillates between two nodes indefinitely. None of the three loop
exit conditions (`parent != null`, `!parentIsRootVisual`, `newTabStop == null`) can ever
be satisfied.
The correct form already exists a few lines below in `GetNextTabStop`, in the
structurally identical `KeyboardNavigationMode.None` branch:
```csharp
current = pIE;
parent = FocusHelpers.GetFocusParent(current); // walks up, converges
```
This changes the three remaining occurrences to match it: one in `GetNextTabStop`, two in
`GetPreviousTabStop`. The two loop initializers outside the `while` (`FocusManager.cs:647`
and `:748`) correctly keep using `focused` and are left alone.
## Reproducing it
The focused element has to be nested **at least one level below** the `Once` container.
When it is a direct child, `GetFocusParent(focused)` happens to return that same container
and the walk terminates by accident - which is likely why this went unnoticed for so long.
Minimal shape (used by both new tests):
```
StackPanel
├── StackPanel [TabNavigation=Once]
│ └── StackPanel
│ └── Button <- focused
└── Button <- expected result for Next
```
Found in a production app: FluentAvalonia's `ContentDialog` calls
`FindNextElement(NavigationDirection.Next, ...)` from its `Loaded` handler to pick an
initial focus target. With focus sitting on a nested `NavigationView` item - the `Once`
container comes from the NavigationView template - opening any dialog hung the app
permanently.
## Scope
Only the programmatic focus APIs go through this code. Pressing Tab is unaffected:
`KeyboardNavigationHandler` uses the separate, WPF-derived implementation in
`Navigation/TabNavigation.cs`, which handles `Once` correctly by passing the container
itself as the new starting point.
## Verification
- Two regression tests added to `InputElement_Focus`, covering both directions.
- Confirmed they actually catch the bug: with the `FocusManager.cs` change reverted, the
Next test ran for 90s using 89.5s of CPU and the Previous test for 60s using 59.6s
before being killed. With the fix both return immediately.
- Full `Avalonia.Base.UnitTests` suite: 2996 tests, 0 failed (2984 passed, 12 skipped).
## Not addressed here
The `Once` branches are asymmetric: `GetPreviousTabStop` returns the container when it is
focusable (`if (FocusHelpers.IsFocusable(parent)) newTabStop = parent;`), `GetNextTabStop`
has no such check. Separately, in the Previous direction this shape ends up returning the
focused element itself via the cycle fallback in `GetTabStopCandidateElement`, rather than
the element preceding the container. Both look like genuine issues, but they are
behavioural questions independent of the hang, so the Previous test only asserts that the
call terminates. Happy to follow up in a separate PR if you would like them fixed.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(focus): previous tab stop search accepted candidates after the focused element
Follow-up to the review feedback on the Previous test: asserting the exact element
exposed that `GetPreviousTabStop` could not produce it. This turned out to be a second,
independent porting error in the same code, so this commit fixes it and tightens both
tests to exact-element assertions.
## Root cause
`GetNextOrPreviousTabStopInternal` accepts an equal-tab-index candidate for the
Previous direction with:
```csharp
if (compareIndexResult < 0 || (((foundCurrent || currentPassed) || compareCurrentForPreviousElement) && compareIndexResult == 0))
```
The WinUI implementation this code is ported from (see
`CFocusManager::GetPreviousTabStopInternal`, faithfully mirrored in Uno's
`FocusManager.mux.cs`) reads:
```cpp
if (compareIndexResult < 0 ||
(((!bFoundCurrent && !bCurrentPassed) || bCurrentCompare) && compareIndexResult == 0))
```
The negations were lost in porting, inverting the condition: since `TabIndex` defaults
to `int.MaxValue`, sibling comparisons are almost always equal, so the Previous search
skipped every element *before* the focused one and accepted elements *after* it. The
Next direction's condition matches WinUI and is untouched.
## Impact
Not limited to the `Once` scenario from the previous commit - `FindNextElement(Previous)`
and `TryMoveFocus(Previous)` were wrong in a plain flat container: with focus on the
third of four buttons, the search returned a following element rather than the preceding
one, and where no following sibling existed it fell back to cycling, handing back the
last focusable element in scope (observed in the Once test as "returns the focused
element itself"). Keyboard Shift+Tab is unaffected as it uses the separate
`TabNavigation.cs` implementation.
## Tests
- `Can_Get_Previous_Element` (new): flat container, focus on target3, asserts target2 -
locks both "skip candidates after the focused element" and "keep the closest
preceding sibling" (not target1).
- `Can_Get_Previous_Element_Out_Of_Container_With_TabNavigation_Once`: now asserts the
exact element (`before`) instead of only termination, per review.
- Verified both fail with the condition reverted and pass with it.
- Full `Avalonia.Base.UnitTests`: 2997 tests, 0 failed (2985 passed, 12 skipped).
## Also spotted, not changed here
The Previous/Cycle branch in `GetPreviousTabStop` calls `GetFirstFocusableElement`
where WinUI calls `GetLastFocusableElement` (wrapping backwards inside a Cycle scope
should land on the last element). Happy to fix that here too if you want it in this PR,
otherwise I can open a separate one.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(focus): previous tab stop wrapped to the first element of a Cycle scope
Third porting divergence found while comparing this code against the WinUI original
(all three sit in the same two functions): the Previous/Cycle branch in
`GetPreviousTabStop` called `GetFirstFocusableElement` where WinUI calls
`GetLastFocusableElement`:
```cpp
// WinUI, CFocusManager::GetPreviousTabStop
if (IsValidTabStopSearchCandidate(pCurrent) && GetTabNavigation(pCurrent) == KeyboardNavigationMode::Cycle)
{
pNewTabStop = GetLastFocusableElement(pCurrent, pCurrent);
break;
}
```
Wrapping backwards inside a Cycle scope must land on the LAST focusable element,
mirroring the forward wrap (last -> first). Taking the first element instead meant
that with focus on the first tab stop of a `TabNavigation=Cycle` container,
`FindNextElement(Previous)` returned the focused element itself and
`TryMoveFocus(Previous)` was a no-op - focus could neither leave the scope (by design)
nor wrap within it (the bug).
Observed against the keyboard-path reference implementation on a Cycle container
[a, b, c] with focus on `a`: `KeyboardNavigationHandler.GetNext(a, Previous)` returns
`c`, this code returned `a`. The forward direction already wrapped correctly
(`c` -> `a`) because the Next branch happens to use the correct element there.
New test `Previous_Wraps_To_Last_Element_In_Cycle_Container` asserts the wrap target;
verified it fails (returns the focused element) with the one-line change reverted.
Full `Avalonia.Base.UnitTests`: 2998 tests, 0 failed (2986 passed, 12 skipped).
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|
2 months ago |
|
|
82dc3b56c1
|
Support {Binding ^} pattern for IObservable DataContext (#21812)
Previously {Binding ^} was not parsed because ParseStart did not
recognize the ^ stream operator. Also, {Binding .^} failed because
ParseDot returned State.End immediately, preventing subsequent
operators.
Changes:
- ParseStart: recognize ^, emit EmptyExpressionNode + StreamNode
- ParseDot: return State.AfterMember instead of State.End, so .^ works
- Add grammar tests for ^ and .^ patterns
|
2 months ago |
|
|
14118ef7cd
|
Fix line break enumerator infinite loop (#21808)
* Add failing test: LineBreakEnumerator infinite loop on empty string * Return false immediately for empty string in LineBreakEnumerator Empty text has no content and should not produce any line break opportunities. Short-circuit in MoveNext before entering the read/rule loop, while keeping the PeekAt EndOfText fix as a defensive safeguard. |
2 months ago |
|
|
c3a5c49699
|
fix(binding): reapply cached source values during UpdateTarget (#21756)
* Added failing test for #21746. * fix(binding): reapply cached source values during UpdateTarget UpdateTarget did not restore an uncommitted explicit two-way target value when the source still matched the binding expression's cached value. Equal-value suppression then prevented ValueStore from receiving the refresh.\n\nTrack the synchronous UpdateTarget rebuild and force publication only for that path, so the source value is reapplied without changing normal binding notification deduplication. The preceding regression test covers the observable behavior in both reflection and compiled binding paths. --------- Co-authored-by: grokys <grokys@users.noreply.github.com> |
2 months ago |
|
|
11564814b3
|
Fixed copypasta-induced bug with custom-hit-test housekeeping (#21769)
|
2 months ago |
|
|
fc9679491a
|
Fixes a dispatcher bug that loses background processing state if jobs were submitted before ReplaceImplementation (#21735)
|
2 months ago |
|
|
ee767d5de1
|
Composition-aware geometries and drawing change detection (#21682)
* Composition-aware geometries * Propagate resource changes in DrawingBrush * Change detection in Drawing * Make IRenderDataGeometry a private API |
3 months ago |
|
|
88a1fc14e0
|
Return false by default from FocusManager.CanHaveFocusableChildren (#21640)
* Add tests around skipping controls for FocusManager #21620 * Return false by default in CanHaveFocusableChildren #21620 Importantly, this will return false for controls that are not focusable (e.g. TextBlock) or that have no focusable childen (e.g. an empty StackPanel) * Add skip tests for FindFirstFocusableElement and FindLastFocusableElement #21620 |
3 months ago |
|
|
893bce4e02
|
Suppress culture flowing with ExecutionContext captured by DispatcherOperation (#21627)
* Fix for #21451 * Move another test to cross tests |
3 months ago |
|
|
12cefeb74a
|
Wayland protocol support (#21448)
|
3 months ago |
|
|
aa1fcb4871
|
Refactor per-draw render data allocations with a binary opcode stream (#21366)
* Add render data opcode enum First step of the Drawing/Nodes binary stream refactor. * Add render data resource table * Add render data stream writer and reader Encodes the opcode stream field-by-field via BinaryPrimitives to avoid unsafe and blittability assumptions. * Add RenderDataStream with recording and replay * Add hit-test walker to RenderDataStream * Add bounds walker to RenderDataStream * Add render data stream serialization * Switch render data to the binary stream * Move node level test coverage to the stream * Delete the render data node classes * Small optimization, stackalloc the render data walker scope stacks * Optimize serialization for blittable types * Encode render data via payload structs, add render data visitor * Rename RenderDataResources.Add to AppendDeserialized * Add effect support to render data stream * Simplify render data read/write with MemoryMarshal |
3 months ago |
|
|
392e3a4459
|
[WASM] Ensure sync context is set before running dispatcher messages (#21462)
* ensure sync context is set before running dispatcher messages * update dispatcher test |
4 months ago |
|
|
b90d84bac7
|
[Text] Fixes culture aware font matching (#21435)
* Make font matching inside the FontCollectionBase implementation culture aware * Aligning `RefineWithCulture` with major text-stack implementations * Revert submodule change * Fix BuildTypefaceWithSynthesis * Add a better unit test coverage for TryMatchCharacter that covers the tiered algorithm * Add some comments to MetaTable parsing Use Span helpers Optimize ScriptExtensions.data |
4 months ago |
|
|
42bba0b859
|
[Text] Unicode and text layout optimizations (#21400)
* perf(text): O(1) width queries on ShapedBuffer, cached LB-class lookup
- ShapedBuffer: lazy, pooled cluster-prefix cache shared across Split;
adds TotalGlyphAdvance / MeasureCharactersThatFit.
- GlyphRun/TextFormatterImpl/Skia GlyphRunImpl: read the cache, drop
duplicate scans; SplitTextRuns now returns firstLength via out.
- LineBreakEnumerator: cache Next/PreviousClass per advance; remove
unused LineBreakPairTable.
- Tests + benchmarks for the new paths and a dotnet-trace harness.
~1.32x faster / -5% alloc on the emoji-wrap micro-benchmark; no
observable behaviour or public API change.
* perf(TextFormatting): inline LineBreakEnumerator rule dispatch
Replace the BreakUnitDelegate[] s_rules array dispatch in
LineBreakEnumerator.ExecuteRules with a sequence of direct static
calls and a `goto Done` early-exit. This removes 42 indirect calls
per codepoint and lets the JIT reason across rule boundaries, which
in turn makes [MethodImpl(AggressiveInlining)] meaningful — JIT
cannot inline through delegate.Invoke, so the attribute was a no-op
in the previous shape.
Selectively apply AggressiveInlining to the small single-condition
rules (LB03, LB04, LB06, LB07, LB08a, LB11–LB15d, LB18, LB20,
LB21b, LB22, LB29, LB31) and let the JIT decide on the larger ones
to avoid bloating the merged ExecuteRules.
The static BreakUnitDelegate[] s_rules array is removed.
Benchmarks (BDN default job, --inProcess, N=13–22, rel. StdDev <1.5%):
UnicodeBreakEnumeratorBenchmark.LineBreakEnumerator_Sequence
Ascii 154.6 µs -> 24.84 µs (6.22x)
Bmp 190.2 µs -> 32.81 µs (5.80x)
Supplementary 227.6 µs -> 37.56 µs (6.06x)
TextLayoutProfile.BuildEmojisWrapped
Before (branch, pre-inline) 804.5 µs / 570.15 KB
After (branch, post-inline) 547.0 µs / 570.15 KB (-32.0%)
vs upstream/master (1061 µs) -> ~1.94x total speedup
No allocation change; CPU-only dispatch reshape. All
LineBreakEnumerator unit tests pass (5/5).
* Refactor ShapedBuffer to share pool storage via IRef + generation counter
Wrap the ArrayPool-rented glyph and cluster-cache arrays in a small
PooledArray<T> disposable and expose them through IRef<T>. Split children
and WithBidiLevel aliases now Clone() the refs instead of borrowing raw
pool arrays, so the backing storage survives until every sibling has
been disposed - eliminating the UAF risk that existed when a parent was
disposed before its children.
Add a per-glyph-holder generation counter (Volatile.Read / Interlocked
.Increment). The indexer setter bumps the counter on every write, and
EnsureClusterCache compares its recorded generation against the holder's
current value, rebuilding on mismatch. This lets us drop the previous
"no mutation after Split/WithBidiLevel" contract: mutations performed
through any sibling now propagate to the others' caches transparently.
Dispose is made idempotent via a _disposed guard so overlapping cache
eviction and TextLine teardown only release the IRefs once.
Adds ShapedBufferSharedStorageTests covering sibling lifetime,
Dispose idempotency, and generation-driven cache invalidation across
Split children and WithBidiLevel aliases.
* test(ShapedBuffer): cover cluster-cache sharing across Split/WithBidiLevel aliases
Add a regression test hook (`ClusterPrefix`) exposing the
backing cluster-prefix array reference, plus two tests that mutate a
parent buffer before aliasing it and assert the alias reuses the
parent's pooled prefix array instead of rebuilding. Guards against
forgetting to propagate `_cacheGeneration` to alias buffers, which
would silently defeat the cached-split fast path.
* Correctly use MathUtilities.LessThanOrClose
---------
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
|
4 months ago |
|
|
0279a557b4
|
Fix RenderTargetBitmap looses effects (#20790)
* add failing test for RenderTargetBitmap_DropShadowEffect * Fix immidiateRenderer with Effect wasn't working as expected * yet another render test * XML comments for newly added members * Address Copilot review * Add another unit test to ensure the recent changes don't get lost at some point in time * address review * Apply Review suggestion Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * inline effectPadding * implement feedback for better bounds handling * Update src/Avalonia.Base/Media/DrawingGroup.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * anohter minor fix * Address PR #20790 review comments - Fix RenderDataEffectNode.Bounds to return null when no children exist, preventing empty effect nodes from incorrectly reporting non-null bounds and causing render artifacts due to incorrect dirty rects. Bounds now inflates child bounds by the effect output padding rather than unioning with BoundsRect. - Move effect output padding inflation from callers into DrawingContext implementations (PlatformDrawingContext, RenderDataDrawingContext) so callers pass content bounds to PushEffect and the API handles inflation internally. Remove pre-inflation from ImmediateRenderer. - Fix DrawingGroup.DrawCore to pass effectBounds (inflated) to PushOpacityMask when an Effect is set, so the opacity mask covers the full effect output region (e.g. shadow/blur extending beyond visual bounds). - Fix DrawingGroup.GetBounds to inflate EffectBounds (which now stores content bounds) by the effect output padding. - Fix existing compile error: Rect.IsEmpty() is a method, not property. - Add failing tests for each of the above before fixing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix DrawingGroup.GetBounds() incorrectly inflating bounds with effect output padding GetBounds() should return content/geometric bounds only, matching WPF behavior. Inflating by GetEffectOutputPadding() caused DrawingImage to shift its coordinate origin by the effect's extent (e.g. a 3.5px shadow offset would displace all content by 3.5px), breaking Should_Render_DrawingGroup_With_Effect render test. Effects render additively outside the content area and must not affect the coordinate system established by GetBounds(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Julien Lebosquain <julien@lebosquain.net> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
4 months ago |
|
|
603b14a439
|
Improve composition hit testing performance with per-visual AABBs (#21310)
* Prototype an AABB tree for hit testing * Some optimizations * Revert runtime knobs and add tests * Avoid rebuilding the whole tree * Revert an invalid optimization * Add a hit test page * Clean up * Format code * Nit * Use weak CompositionVisual reference in server-side * Bucket composition hit-test AABB tree by child order * Use readback revisions for AABB hit-test updates |
4 months ago |
|
|
a77f08d675
|
[Text] Move Unicode trie generation to a dedicated Nuke-driven tool (#21391)
* [Text] Move Unicode trie generation to a dedicated Nuke-driven tool The trie and enum generators used to live as [Fact(Skip = ...)] tests in Avalonia.Base.UnitTests, writing to a local Generated/ folder that had to be hand-copied into src/Avalonia.Base/Media/TextFormatting/Unicode/. Move them into a standalone tool project invoked by a new GenerateUnicodeData Nuke target that writes the canonical files in place. - New src/tools/Avalonia.UnicodeTrieGenerator console app (mirrors the GenerateCppHeaders pattern), signed via SharedVersion.props and added to Avalonia.Base's InternalsVisibleTo for UnicodeTrieBuilder access. - UCD downloads are cached under artifacts/ucd-cache/<version>/ so reruns work offline; the target accepts --output and --cache args. - LineBreakClass and WordBreakClass orderings now come from PropertyValueAliases (with hot-path tags seeded at the front for cache density), removing the BreakPairTable.txt resource and the dead BreakPairTable.cs writer that nothing in src/ referenced. - ParseDataEntries dedupes by Name OR Tag so seeds can use friendlier names (Carriage_Return) than UCD's WB primaries (CR). - Deprecated WB classes (E_Base, E_Modifier, Glue_After_Zwj, E_Base_GAZ) are filtered out — they have no codepoint mappings. - Conformance tests stay in the test project, repointed at a small UnicodeTestData.Ucd constant. Regenerating into the canonical Unicode directory produces a zero diff against the previously committed enums and tries, confirming the port preserves output byte-for-byte. Invoke with `./build.cmd GenerateUnicodeData`. * Align generated file names Validate all tries Unify UCD path * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Make the trie generation standalone --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
4 months ago |
|
|
ed836146d6
|
Roslyn generator for generating cross-thread call proxies (#21384)
|
4 months ago |
|
|
be6bc063f1
|
Pass original logical size to render targets (#21380)
* Pass original logical size to render targets * Change FromSizeCeiling method to internal access * api diff again? |
4 months ago |
|
|
aa7dcf1a02
|
Allow `Dispatcher` to be converted to a `TaskScheduler` (#21032)
* Allow Dispatcher to be implicitly cast to TaskScheduler * API change requests * Cache one scheduler per priority * Cache a TaskScheduler in each sync context |
4 months ago |
|
|
6fa084abf2
|
[Text] Implement Unicode word segmentation and update to Unicode v17 (#21361)
* Add word break support and use it for ellipsis * Regenerate Unicode text-formatting data to v17 and fix issues --------- Co-authored-by: Jumar Macato <16554748+jmacato@users.noreply.github.com> Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com> |
4 months ago |