Skip to content

Commit 5d63647

Browse files
committed
Merge in 'release/5.0' changes
2 parents cb5ea18 + 59bdffc commit 5d63647

File tree

7 files changed

+95
-75
lines changed

7 files changed

+95
-75
lines changed

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Common/StylusLogic.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ internal enum FlickScrollDirection
180180
// Caches the pointer stack enabled state
181181
private static bool? _isPointerStackEnabled = null;
182182

183+
// Caches TransformToDevice matrices per DpiScale2
184+
private readonly Dictionary<DpiScale2, Matrix> _transformToDeviceMatrices = new Dictionary<DpiScale2, Matrix>();
185+
183186
#endregion
184187

185188
#region Construction/Initilization
@@ -402,19 +405,48 @@ protected void ReadSystemConfig()
402405
/// </summary>
403406
internal abstract TabletDeviceCollection TabletDevices { get; }
404407

408+
/// <summary>
409+
/// Acquires and caches the TransformToDevice matrix from a specific HwndSource.
410+
/// </summary>
411+
/// <remarks>
412+
/// The caching here is done at a per DPI level. TransformToDevice only matters for a
413+
/// specific DpiScale, so there is no need to spend space caching it per HwndSource.
414+
/// </remarks>
415+
/// <param name="source">The source of DpiScale and matrix transforms</param>
416+
/// <returns>The TransformToDevice matrix corresponding to the DpiScale of the source</returns>
417+
protected Matrix GetAndCacheTransformToDeviceMatrix(PresentationSource source)
418+
{
419+
var hwndSource = source as HwndSource;
420+
Matrix toDevice = Matrix.Identity;
421+
422+
if (hwndSource?.CompositionTarget != null)
423+
{
424+
// If we have not yet seen this DPI, store the matrix for it.
425+
if (!_transformToDeviceMatrices.ContainsKey(hwndSource.CompositionTarget.CurrentDpiScale))
426+
{
427+
_transformToDeviceMatrices[hwndSource.CompositionTarget.CurrentDpiScale] = hwndSource.CompositionTarget.TransformToDevice;
428+
Debug.Assert(_transformToDeviceMatrices[hwndSource.CompositionTarget.CurrentDpiScale].HasInverse);
429+
}
430+
431+
toDevice = _transformToDeviceMatrices[hwndSource.CompositionTarget.CurrentDpiScale];
432+
}
433+
434+
return toDevice;
435+
}
436+
405437
/// <summary>
406438
/// Converts measure units to tablet device coordinates
407439
/// </summary>
408440
/// <param name="measurePoint"></param>
409441
/// <returns></returns>
410-
internal abstract Point DeviceUnitsFromMeasureUnits(Point measurePoint);
442+
internal abstract Point DeviceUnitsFromMeasureUnits(PresentationSource source, Point measurePoint);
411443

412444
/// <summary>
413445
/// Converts device units to measure units
414446
/// </summary>
415447
/// <param name="measurePoint"></param>
416448
/// <returns></returns>
417-
internal abstract Point MeasureUnitsFromDeviceUnits(Point measurePoint);
449+
internal abstract Point MeasureUnitsFromDeviceUnits(PresentationSource source, Point measurePoint);
418450

419451
/// <summary>
420452
/// Updates the stylus capture for the particular stylus device

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Pointer/PointerLogic.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -475,13 +475,12 @@ internal override TabletDeviceCollection TabletDevices
475475
/// </summary>
476476
/// <param name="measurePoint">The point in measure units</param>
477477
/// <returns>The point in device units</returns>
478-
internal override Point DeviceUnitsFromMeasureUnits(Point measurePoint)
478+
internal override Point DeviceUnitsFromMeasureUnits(PresentationSource source, Point measurePoint)
479479
{
480-
481480
// We can possibly get here with no current device. This happens from a certain order of mouse capture.
482481
// In that case, default to identity matrix as the capture units are going to be from the mouse.
483482
// Otherwise, transform using the tablet for the current stylus device.
484-
Point pt = measurePoint * (_currentStylusDevice?.ActiveSource?.CompositionTarget?.TransformToDevice ?? Matrix.Identity);
483+
Point pt = measurePoint * GetAndCacheTransformToDeviceMatrix(source);
485484

486485
// Make sure we return whole numbers (pixels are whole numbers)
487486
return new Point(Math.Round(pt.X), Math.Round(pt.Y));
@@ -492,13 +491,12 @@ internal override Point DeviceUnitsFromMeasureUnits(Point measurePoint)
492491
/// </summary>
493492
/// <param name="devicePoint">The point in device units</param>
494493
/// <returns>The point in measure units</returns>
495-
internal override Point MeasureUnitsFromDeviceUnits(Point devicePoint)
494+
internal override Point MeasureUnitsFromDeviceUnits(PresentationSource source, Point devicePoint)
496495
{
497-
498496
// We can possibly get here with no current device. This happens from a certain order of mouse capture.
499497
// In that case, default to identity matrix as the capture units are going to be from the mouse.
500498
// Otherwise, transform using the tablet for the current stylus device.
501-
Point pt = devicePoint * (_currentStylusDevice?.ActiveSource?.CompositionTarget?.TransformFromDevice ?? Matrix.Identity);
499+
Point pt = devicePoint * GetAndCacheTransformToDeviceMatrix(source);
502500

503501
// Make sure we return whole numbers (pixels are whole numbers)
504502
return new Point(Math.Round(pt.X), Math.Round(pt.Y));
@@ -1273,7 +1271,7 @@ private void UpdateTapCount(NotifyInputEventArgs args)
12731271

12741272
int elapsedTime = Math.Abs(unchecked(stylusDownEventArgs.Timestamp - _lastTapTimeTicks));
12751273

1276-
Point ptPixels = DeviceUnitsFromMeasureUnits(ptClient);
1274+
Point ptPixels = DeviceUnitsFromMeasureUnits(stylusDevice.CriticalActiveSource, ptClient);
12771275

12781276
Size doubleTapSize = stylusDevice.PointerTabletDevice.DoubleTapSize;
12791277

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Pointer/PointerStylusDevice.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ internal void ChangeStylusCapture(IInputElement stylusCapture, CaptureMode captu
10971097
// See if we need to update over for subtree mode.
10981098
if (CapturedMode == CaptureMode.SubTree && _inputSource != null && _inputSource.Value != null)
10991099
{
1100-
Point pt = _pointerLogic.DeviceUnitsFromMeasureUnits(GetPosition(null));
1100+
Point pt = _pointerLogic.DeviceUnitsFromMeasureUnits(_inputSource.Value, GetPosition(null));
11011101
inputElementHit = FindTarget(_inputSource.Value, pt);
11021102
}
11031103

@@ -1109,7 +1109,7 @@ internal void ChangeStylusCapture(IInputElement stylusCapture, CaptureMode captu
11091109
if (_inputSource != null && _inputSource.Value != null)
11101110
{
11111111
Point pt = GetPosition(null); // relative to window (root element)
1112-
pt = _pointerLogic.DeviceUnitsFromMeasureUnits(pt); // change back to device coords.
1112+
pt = _pointerLogic.DeviceUnitsFromMeasureUnits(_inputSource.Value, pt); // change back to device coords.
11131113
IInputElement currentOver = Input.StylusDevice.GlobalHitTest(_inputSource.Value, pt);
11141114
ChangeStylusOver(currentOver);
11151115
}

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Wisp/PenContexts.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ internal void InvokeStylusPluginCollection(RawStylusInputReport inputReport)
440440
{
441441
// Create new RawStylusInput to send
442442
GeneralTransformGroup transformTabletToView = new GeneralTransformGroup();
443-
transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
443+
transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(stylusDevice.CriticalActiveSource, stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
444444
transformTabletToView.Children.Add(currentPic.ViewToElement); // Make it relative to the element.
445445
transformTabletToView.Freeze(); // Must be frozen for multi-threaded access.
446446

@@ -459,7 +459,7 @@ internal void InvokeStylusPluginCollection(RawStylusInputReport inputReport)
459459
// The transformTabletToView matrix and plugincollection rects though can change based
460460
// off of layout events which is why we need to lock this.
461461
GeneralTransformGroup transformTabletToView = new GeneralTransformGroup();
462-
transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
462+
transformTabletToView.Children.Add(new MatrixTransform(_stylusLogic.GetTabletToViewTransform(stylusDevice.CriticalActiveSource, stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
463463
transformTabletToView.Children.Add(pic.ViewToElement); // Make it relative to the element.
464464
transformTabletToView.Freeze(); // Must be frozen for multi-threaded access.
465465

@@ -512,7 +512,7 @@ internal StylusPlugInCollection TargetPlugInCollection(RawStylusInputReport inpu
512512
ptTablet = ptTablet * stylusDevice.TabletDevice.TabletDeviceImpl.TabletToScreen;
513513
ptTablet.X = (int)Math.Round(ptTablet.X); // Make sure we snap to whole window pixels.
514514
ptTablet.Y = (int)Math.Round(ptTablet.Y);
515-
ptTablet = _stylusLogic.MeasureUnitsFromDeviceUnits(ptTablet); // change to measured units now.
515+
ptTablet = _stylusLogic.MeasureUnitsFromDeviceUnits(stylusDevice.CriticalActiveSource, ptTablet); // change to measured units now.
516516

517517
pic = HittestPlugInCollection(ptTablet); // Use cached rectangles for UIElements.
518518
}
@@ -556,6 +556,8 @@ StylusPlugInCollection HittestPlugInCollection(Point pt)
556556
return null;
557557
}
558558

559+
internal HwndSource InputSource { get { return _inputSource.Value; } }
560+
559561
/////////////////////////////////////////////////////////////////////
560562

561563
internal SecurityCriticalData<HwndSource> _inputSource;

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Wisp/WispLogic.cs

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ private void PreNotifyInput(object sender, NotifyInputEventArgs e)
10251025
if (!_inDragDrop && !rawStylusInputReport.PenContext.Contexts.IsWindowDisabled && !stylusDevice.IgnoreStroke)
10261026
{
10271027
Point position = stylusDevice.GetRawPosition(null);
1028-
position = DeviceUnitsFromMeasureUnits(position); // change back to device coords.
1028+
position = DeviceUnitsFromMeasureUnits(stylusDevice.CriticalActiveSource, position); // change back to device coords.
10291029
IInputElement target = stylusDevice.FindTarget(stylusDevice.CriticalActiveSource, position);
10301030
SelectStylusDevice(stylusDevice, target, true);
10311031
}
@@ -1077,8 +1077,8 @@ private void PreNotifyInput(object sender, NotifyInputEventArgs e)
10771077
bBarrelPressed = true;
10781078
}
10791079

1080-
Point pPixelPoint = DeviceUnitsFromMeasureUnits(ptClient);
1081-
Point pLastPixelPoint = DeviceUnitsFromMeasureUnits(stylusDevice.LastTapPoint);
1080+
Point pPixelPoint = DeviceUnitsFromMeasureUnits(stylusDevice.CriticalActiveSource, ptClient);
1081+
Point pLastPixelPoint = DeviceUnitsFromMeasureUnits(stylusDevice.CriticalActiveSource, stylusDevice.LastTapPoint);
10821082

10831083
// How long since the last click? (deals with tickcount wrapping too)
10841084
// Here's some info on how this works...
@@ -2660,6 +2660,8 @@ private void VerifyStylusPlugInCollectionTarget(RawStylusInputReport rawStylusIn
26602660
rawStylusInputReport.RawStylusInput = null;
26612661
}
26622662

2663+
WispStylusDevice stylusDevice = rawStylusInputReport.StylusDevice.As<WispStylusDevice>();
2664+
26632665
// See if we need to build up an RSI to send to the plugincollection (due to a mistarget).
26642666
bool sendRawStylusInput = false;
26652667
if (targetPIC != null && rawStylusInputReport.RawStylusInput == null)
@@ -2668,7 +2670,7 @@ private void VerifyStylusPlugInCollectionTarget(RawStylusInputReport rawStylusIn
26682670
// The transformTabletToView matrix and plugincollection rects though can change based
26692671
// off of layout events which is why we need to lock this.
26702672
GeneralTransformGroup transformTabletToView = new GeneralTransformGroup();
2671-
transformTabletToView.Children.Add(new MatrixTransform(GetTabletToViewTransform(rawStylusInputReport.StylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
2673+
transformTabletToView.Children.Add(new MatrixTransform(GetTabletToViewTransform(stylusDevice.CriticalActiveSource, stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
26722674
transformTabletToView.Children.Add(targetPIC.ViewToElement); // Make it relative to the element.
26732675
transformTabletToView.Freeze(); // Must be frozen for multi-threaded access.
26742676

@@ -2677,8 +2679,6 @@ private void VerifyStylusPlugInCollectionTarget(RawStylusInputReport rawStylusIn
26772679
sendRawStylusInput = true;
26782680
}
26792681

2680-
WispStylusDevice stylusDevice = rawStylusInputReport.StylusDevice.As<WispStylusDevice>();
2681-
26822682
// Now fire the confirmed enter/leave events as necessary.
26832683
StylusPlugInCollection currentTarget = stylusDevice.CurrentVerifiedTarget;
26842684
if (targetPIC != currentTarget)
@@ -2689,7 +2689,7 @@ private void VerifyStylusPlugInCollectionTarget(RawStylusInputReport rawStylusIn
26892689
if (originalRSI == null)
26902690
{
26912691
GeneralTransformGroup transformTabletToView = new GeneralTransformGroup();
2692-
transformTabletToView.Children.Add(new MatrixTransform(GetTabletToViewTransform(stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
2692+
transformTabletToView.Children.Add(new MatrixTransform(GetTabletToViewTransform(stylusDevice.CriticalActiveSource, stylusDevice.TabletDevice))); // this gives matrix in measured units (not device)
26932693
transformTabletToView.Children.Add(currentTarget.ViewToElement); // Make it relative to the element.
26942694
transformTabletToView.Freeze(); // Must be frozen for multi-threaded access.
26952695
originalRSI = new RawStylusInput(rawStylusInputReport, transformTabletToView, currentTarget);
@@ -3109,16 +3109,7 @@ internal void RegisterHwndForInput(InputManager inputManager, PresentationSource
31093109
{
31103110
HwndSource hwndSource = (HwndSource)inputSource;
31113111

3112-
// Query the transform from HwndTarget when the first window is created.
3113-
if (!_transformInitialized)
3114-
{
3115-
if (hwndSource != null && hwndSource.CompositionTarget != null)
3116-
{
3117-
_transformToDevice = hwndSource.CompositionTarget.TransformToDevice;
3118-
Debug.Assert(_transformToDevice.HasInverse);
3119-
_transformInitialized = true;
3120-
}
3121-
}
3112+
GetAndCacheTransformToDeviceMatrix(hwndSource);
31223113

31233114
// Keep track so we don't bother looking for changes if someone happened to query this before
31243115
// an Avalon window was created where we get TabletAdd/Removed notification.
@@ -3563,14 +3554,14 @@ internal object ProcessDisplayChanged(object oInput)
35633554

35643555
/////////////////////////////////////////////////////////////////////
35653556

3566-
internal Matrix GetTabletToViewTransform(TabletDevice tabletDevice)
3557+
internal Matrix GetTabletToViewTransform(PresentationSource source, TabletDevice tabletDevice)
35673558
{
35683559
// Inking is offset under 120 DPI
35693560
// Changet the TabletToViewTransform matrix to take DPI into account. The default
35703561
// value is 96 DPI in Avalon. The device DPI value is cached after the first call
35713562
// to this function.
35723563

3573-
Matrix matrix = _transformToDevice;
3564+
Matrix matrix = GetAndCacheTransformToDeviceMatrix(source);
35743565
matrix.Invert();
35753566
return matrix * tabletDevice.As<TabletDeviceBase>().TabletToScreen;
35763567
}
@@ -3580,9 +3571,9 @@ internal Matrix GetTabletToViewTransform(TabletDevice tabletDevice)
35803571
/// </summary>
35813572
/// <param name="measurePoint">The point to transform, in measure units</param>
35823573
/// <returns>The point in device coordinates</returns>
3583-
internal override Point DeviceUnitsFromMeasureUnits(Point measurePoint)
3574+
internal override Point DeviceUnitsFromMeasureUnits(PresentationSource source, Point measurePoint)
35843575
{
3585-
Point pt = measurePoint * _transformToDevice;
3576+
Point pt = measurePoint * GetAndCacheTransformToDeviceMatrix(source);
35863577
pt.X = (int)Math.Round(pt.X); // Make sure we return whole numbers (pixels are whole numbers)
35873578
pt.Y = (int)Math.Round(pt.Y);
35883579
return pt;
@@ -3593,9 +3584,9 @@ internal override Point DeviceUnitsFromMeasureUnits(Point measurePoint)
35933584
/// </summary>
35943585
/// <param name="measurePoint">The point to transform, in measure units</param>
35953586
/// <returns>The point in device coordinates</returns>
3596-
internal override Point MeasureUnitsFromDeviceUnits(Point measurePoint)
3587+
internal override Point MeasureUnitsFromDeviceUnits(PresentationSource source, Point measurePoint)
35973588
{
3598-
Matrix matrix = _transformToDevice;
3589+
Matrix matrix = GetAndCacheTransformToDeviceMatrix(source);
35993590
matrix.Invert();
36003591
return measurePoint * matrix;
36013592
}
@@ -3647,11 +3638,6 @@ internal long IncrementVersion()
36473638

36483639
/////////////////////////////////////////////////////////////////////
36493640

3650-
private Matrix _transformToDevice = Matrix.Identity;
3651-
private bool _transformInitialized;
3652-
3653-
/////////////////////////////////////////////////////////////////////
3654-
36553641
private SecurityCriticalData<InputManager> _inputManager;
36563642

36573643
DispatcherOperationCallback _dlgInputManagerProcessInput;

0 commit comments

Comments
 (0)