From 528ae2f03d92295f38eef042115e1898f47384f4 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 28 Jun 2021 16:33:30 -0400 Subject: [PATCH 1/2] Remove lots of unnecessary string allocations Low-hanging fruit. Yay, span. --- .../MS/internal/FontCache/FontCacheUtil.cs | 2 +- .../IO/Packaging/ByteRangeDownloader.cs | 14 +++--- .../TextFormatting/NumberSubstitution.cs | 13 ++--- .../PresentationCore/PresentationCore.csproj | 1 + .../Windows/Input/InputScopeConverter.cs | 16 ++++--- .../Media/Animation/KeyTimeConverter.cs | 2 +- .../Windows/Media/Animation/Timeline.cs | 6 +-- .../System/Windows/Media/CharacterMetrics.cs | 4 +- .../System/Windows/Media/GlyphsSerializer.cs | 2 +- .../Windows/Media/Imaging/PropVariant.cs | 2 +- .../Windows/Navigation/BaseUriHelper.cs | 3 +- .../System/Windows/dataobject.cs | 15 ++++-- .../Internal/PtsHost/ListMarkerSourceInfo.cs | 27 +++++------ .../Microsoft/Win32/FileDialog.cs | 23 ++++----- .../PresentationFramework.csproj | 1 + .../System/Windows/Controls/ComboBox.cs | 2 +- .../Controls/DataGridLengthConverter.cs | 4 +- .../Controls/ItemContainerGenerator.cs | 6 +-- .../System/Windows/Controls/TextSearch.cs | 14 +++--- .../Controls/VirtualizingStackPanel.cs | 4 +- .../Windows/Documents/FixedSOMTextRun.cs | 13 ++--- .../System/Windows/Documents/FixedSchema.cs | 13 +++-- .../Windows/Documents/RtfToXamlReader.cs | 48 +++++++------------ .../Windows/Documents/XamlToRtfWriter.cs | 27 +++++------ .../System/Windows/Documents/glyphs.cs | 30 ++++++------ .../Windows/Markup/Baml2006/Baml2006Reader.cs | 13 +++-- .../ExtensionSimplifierMarkupObject.cs | 6 +-- .../Windows/Markup/Primitives/MarkupWriter.cs | 4 +- .../Markup/XamlFigureLengthSerializer.cs | 4 +- .../Markup/XamlGridLengthSerializer.cs | 4 +- .../System/Windows/PropertyPath.cs | 5 +- .../System/Windows/PropertyPathConverter.cs | 6 +-- .../DocumentApplicationDocumentViewer.cs | 10 ++-- .../src/PresentationUI/PresentationUI.csproj | 1 + .../Packaging/XpsFixedPageReaderWriter.cs | 16 +++---- .../src/ReachFramework/ReachFramework.csproj | 1 + .../Serialization/XpsFontSubsetter.cs | 12 ++--- .../ReachDocumentSequenceSerializer.cs | 11 ++--- .../ReachDocumentSequenceSerializerAsync.cs | 11 ++--- .../manager/ReachFixedDocumentSerializer.cs | 11 ++--- .../ReachFixedDocumentSerializerAsync.cs | 11 ++--- .../manager/ReachFixedPageSerializer.cs | 11 ++--- .../manager/ReachFixedPageSerializerAsync.cs | 11 ++--- .../manager/XpsOMFixedPageSerializer.cs | 11 ++--- .../Ribbon/RibbonControlLengthConverter.cs | 4 +- .../System.Windows.Controls.Ribbon.csproj | 1 + .../src/System.Xaml/System.Xaml.csproj | 1 + .../System/Xaml/MS/Impl/KnownStrings.cs | 5 ++ .../Xaml/Schema/ClrNamespaceUriParser.cs | 4 +- .../Internal/AutomationProxies/WordBreaker.cs | 4 +- 50 files changed, 223 insertions(+), 247 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontCacheUtil.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontCacheUtil.cs index f482c460556..f54f8b9dca2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontCacheUtil.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontCacheUtil.cs @@ -661,7 +661,7 @@ private static string NormalizeFontFamilyReference(string fontFamilyReference, i { // No fragment separator. The entire string is a family name so convert to uppercase // and add a fragment separator at the beginning. - return "#" + fontFamilyReference.Substring(startIndex, length).ToUpperInvariant(); + return string.Concat("#", fontFamilyReference.AsSpan(startIndex, length)).ToUpperInvariant(); } else if (fragmentIndex + 1 == startIndex + length) { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/ByteRangeDownloader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/ByteRangeDownloader.cs index 381de65dabc..164505d898a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/ByteRangeDownloader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/ByteRangeDownloader.cs @@ -798,13 +798,13 @@ static private bool CheckContentRange(WebHeaderCollection responseHeaders, int b } // Get the first byte offset of the range (XXX) - int firstByteOffset = Int32.Parse(contentRange.Substring(ByteRangeUnit.Length, + int firstByteOffset = Int32.Parse(contentRange.AsSpan(ByteRangeUnit.Length, index - ByteRangeUnit.Length), NumberStyles.None, NumberFormatInfo.InvariantInfo); - contentRange = contentRange.Substring(index + 1); + ReadOnlySpan contentRangeSpan = contentRange.AsSpan(index + 1); // ContentRange: YYY/ZZZ - index = contentRange.IndexOf('/'); + index = contentRangeSpan.IndexOf('/'); if (index == -1) { @@ -812,18 +812,18 @@ static private bool CheckContentRange(WebHeaderCollection responseHeaders, int b } // Get the last byte offset of the range (YYY) - int lastByteOffset = Int32.Parse(contentRange.Substring(0, index), NumberStyles.None, NumberFormatInfo.InvariantInfo); + int lastByteOffset = Int32.Parse(contentRangeSpan.Slice(0, index), NumberStyles.None, NumberFormatInfo.InvariantInfo); // Get the instance length // ContentRange: ZZZ - contentRange = contentRange.Substring(index + 1); - if (String.CompareOrdinal(contentRange, "*") != 0) + contentRangeSpan = contentRangeSpan.Slice(index + 1); + if (!contentRangeSpan.Equals("*", StringComparison.Ordinal)) { // Note: for firstByteOffset and lastByteOffset, we are using Int32.Parse to make sure Int32.Parse to throw // if it is not an integer or the integer is bigger than Int32 since HttpWebRequest.AddRange // only supports Int32 // Once HttpWebRequest.AddRange start supporting Int64 we should change it to Int64 and long - Int32.Parse(contentRange, NumberStyles.None, NumberFormatInfo.InvariantInfo); + Int32.Parse(contentRangeSpan, NumberStyles.None, NumberFormatInfo.InvariantInfo); } // The response is considered to be successful if diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/NumberSubstitution.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/NumberSubstitution.cs index d75a4aa834a..7f974fdff3e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/NumberSubstitution.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/NumberSubstitution.cs @@ -497,21 +497,18 @@ private CultureInfo CreateTraditionalCulture(CultureInfo numberCulture, int firs { for (int i = 0; i < 10; ++i) { - digits[i] = new string((char)(firstDigit + i), 1); + digits[i] = ((char)(firstDigit + i)).ToString(); } } else { + Span twoChars = stackalloc char[2]; for (int i = 0; i < 10; ++i) { int n = firstDigit + i - 0x10000; - - digits[i] = new string( - new char[] { - (char)((n >> 10) | 0xD800), // high surrogate - (char)((n & 0x03FF) | 0xDC00) // low surrogate - } - ); + twoChars[0] = (char)((n >> 10) | 0xD800); // high surrogate + twoChars[1] = (char)((n & 0x03FF) | 0xDC00); // low surrogate + digits[i] = new string(twoChars); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj index 51b9c1708ae..4ecf9a591c2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj @@ -1383,6 +1383,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputScopeConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputScopeConverter.cs index e5aaaf51718..e00c119ac3b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputScopeConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputScopeConverter.cs @@ -109,14 +109,18 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c if (null != stringSource) { - stringSource = stringSource.Trim(); + ReadOnlySpan spanSource = stringSource; + spanSource = spanSource.Trim(); - if (-1 != stringSource.LastIndexOf('.')) - stringSource = stringSource.Substring(stringSource.LastIndexOf('.')+1); - - if (!stringSource.Equals(String.Empty)) + int periodPos = spanSource.LastIndexOf('.'); + if (periodPos != -1) { - sn = (InputScopeNameValue)Enum.Parse(typeof(InputScopeNameValue), stringSource); + spanSource = spanSource.Slice(periodPos + 1); + } + + if (!spanSource.IsEmpty) + { + sn = Enum.Parse(spanSource); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs index eecb78bb77c..6819fa6271c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs @@ -195,7 +195,7 @@ public override object ConvertTo( keyTime.Percent * 100.0, destinationType); - return returnValue + _percentCharacter[0].ToString(); + return string.Concat(returnValue, (ReadOnlySpan)_percentCharacter); case KeyTimeType.TimeSpan: diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Timeline.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Timeline.cs index 8b40e4bfc4d..2d52535a990 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Timeline.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Timeline.cs @@ -1093,17 +1093,17 @@ internal void BuildInfo(System.Text.StringBuilder builder, int depth, bool inclu if (AccelerationRatio != 0.0f) { builder.Append(", AccelerationRatio = "); - builder.Append(AccelerationRatio.ToString()); + builder.Append(AccelerationRatio); } if (AutoReverse != false) { builder.Append(", AutoReverse = "); - builder.Append(AutoReverse.ToString()); + builder.Append(AutoReverse); } if (DecelerationRatio != 0.0f) { builder.Append(", DecelerationRatio = "); - builder.Append(DecelerationRatio.ToString()); + builder.Append(DecelerationRatio); } if (Duration != Duration.Automatic) { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/CharacterMetrics.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/CharacterMetrics.cs index c185b3819ed..f4153bf05bd 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/CharacterMetrics.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/CharacterMetrics.cs @@ -168,7 +168,7 @@ private static double[] ParseMetrics(string s) if (k > i) { // Non-empty field; convert it to double. - string field = s.Substring(i, k - i); + ReadOnlySpan field = s.AsSpan(i, k - i); if (!double.TryParse( field, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, @@ -176,7 +176,7 @@ private static double[] ParseMetrics(string s) out metrics[fieldIndex] )) { - throw new ArgumentException(SR.Get(SRID.CannotConvertStringToType, field, "double")); + throw new ArgumentException(SR.Get(SRID.CannotConvertStringToType, field.ToString(), "double")); } } else if (fieldIndex < NumRequiredFields) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphsSerializer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphsSerializer.cs index afa4fbca723..6a0989f2d12 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphsSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphsSerializer.cs @@ -216,7 +216,7 @@ private void AddGlyph(int glyph, int sourceCharacter) // remove trailing commas RemoveTrailingCharacters(_glyphStringBuider, GlyphSubEntrySeparator); _glyphStringBuider.Append(GlyphSeparator); - _indicesStringBuider.Append(_glyphStringBuider.ToString()); + _indicesStringBuider.Append(_glyphStringBuider); // reset for next glyph _glyphStringBuider.Length = 0; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/PropVariant.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/PropVariant.cs index b6b7e7922f5..15a696c3c83 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/PropVariant.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/PropVariant.cs @@ -364,7 +364,7 @@ internal void Init(object value) else if (value is char) { varType = (ushort)VarEnum.VT_LPSTR; - pszVal = Marshal.StringToCoTaskMemAnsi(new String(new char[] { (char)value })); + pszVal = Marshal.StringToCoTaskMemAnsi(new String(stackalloc char[] { (char)value })); } else if (type == typeof(short)) { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Navigation/BaseUriHelper.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Navigation/BaseUriHelper.cs index a2bd2085477..52a0a6dc046 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Navigation/BaseUriHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Navigation/BaseUriHelper.cs @@ -643,8 +643,7 @@ private static byte[] ParseAssemblyKey(string assemblyKey) byte[] keyToken = new byte[byteCount]; for (int i = 0; i < byteCount; i++) { - string byteString = assemblyKey.Substring(i * 2, 2); - keyToken[i] = byte.Parse(byteString, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + keyToken[i] = byte.Parse(assemblyKey.AsSpan(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); } return keyToken; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs index 2c9bcb05705..f00e90f611d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/dataobject.cs @@ -1939,7 +1939,10 @@ private int SaveFileListToHandle(IntPtr handle, string[] files, bool doNotReallo currentPtr = (IntPtr)((long)currentPtr + (files[i].Length * 2)); // Terminate the each of file string. - Marshal.Copy(new char[] { '\0' }, 0, currentPtr, 1); + unsafe + { + *(char*)currentPtr = '\0'; + } // Increase the current pointer by 2 since it is a unicode. currentPtr = (IntPtr)((long)currentPtr + 2); @@ -1948,7 +1951,10 @@ private int SaveFileListToHandle(IntPtr handle, string[] files, bool doNotReallo #pragma warning restore 6523 // Terminate the string and add 2bytes since it is a unicode. - Marshal.Copy(new char[] { '\0' }, 0, currentPtr, 1); + unsafe + { + *(char*)currentPtr = '\0'; + } } finally { @@ -2000,7 +2006,10 @@ private int SaveStringToHandle(IntPtr handle, string str, bool unicode, bool doN // Terminate the string becasue of GlobalReAlloc GMEM_ZEROINIT will zero // out only the bytes it adds to the memory object. It doesn't initialize // any of the memory that existed before the call. - Marshal.Copy(new char[] { '\0' }, 0, (IntPtr)((ulong)ptr + (ulong)chars.Length * 2), 1); + unsafe + { + *(char*)(IntPtr)((ulong)ptr + (ulong)chars.Length * 2) = '\0'; + } } finally { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/ListMarkerSourceInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/ListMarkerSourceInfo.cs index 9b58fba5ed8..d78ea8ffd69 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/ListMarkerSourceInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/ListMarkerSourceInfo.cs @@ -160,15 +160,15 @@ private static string ConvertNumberToString(int number, bool oneBased, string nu Invariant.Assert(number >= 0); - char[] result; int b = numericSymbols.Length; if (number < b) { // Optimize common case of single-digit numbers. - // Optimize common case of single-digit numbers. - result = new char[2]; // digit + suffix - result[0] = numericSymbols[number]; - result[1] = NumberSuffix; + return new string(stackalloc char[2] // digit + suffix + { + numericSymbols[number], + NumberSuffix + }); } else { @@ -190,17 +190,16 @@ private static string ConvertNumberToString(int number, bool oneBased, string nu } // Build string in reverse order starting with suffix. - // Build string in reverse order starting with suffix. - result = new char[digits + 1]; // digits + suffix - result[digits] = NumberSuffix; - for (int i = digits - 1; i >= 0; --i) + return string.Create(digits + 1, (numericSymbols, number, b, disjoint), (result, state) => // digits + suffix { - result[i] = numericSymbols[number % b]; - number = (number / b) - disjoint; - } + result[result.Length - 1] = NumberSuffix; + for (int i = result.Length - 2; i >= 0; --i) + { + state.number = Math.DivRem(state.number, state.b, out int remainder) - state.disjoint; + result[i] = state.numericSymbols[remainder]; + } + }); } - - return new string(result); } /// diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/FileDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/FileDialog.cs index 553e3c6f125..1b26d38d1e7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/FileDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/FileDialog.cs @@ -1464,23 +1464,24 @@ private bool ProcessFileNames() // somehow slipped through. // // Strip out any extension that may be remaining and place the rest - // of the filename in s. - // - // Changed to use StringBuilder for perf reasons as per FxCop CA1818 - StringBuilder s = new StringBuilder(fileName.Substring(0, fileName.Length - currentExtension.Length)); - // we don't want to append the extension if it contains wild cards - if (extensions[j].IndexOfAny(new char[] { '*', '?' }) == -1) + // of the filename in s. + + string newFilename; + if (((ReadOnlySpan)extensions[j]).IndexOfAny('*', '?') != -1) + { + // we don't want to append the extension if it contains wild cards + newFilename = fileName.Substring(0, fileName.Length - currentExtension.Length); + } + else { - // No wildcards, so go ahead and append - s.Append("."); - s.Append(extensions[j]); + newFilename = string.Concat(fileName.AsSpan(0, fileName.Length - currentExtension.Length), ".", extensions[j]); } // If OFN_FILEMUSTEXIST is not set, or if it is set but the filename we generated // does in fact exist, we update fileName and stop trying new extensions. - if (!GetOption(NativeMethods.OFN_FILEMUSTEXIST) || File.Exists(s.ToString())) + if (!GetOption(NativeMethods.OFN_FILEMUSTEXIST) || File.Exists(newFilename)) { - fileName = s.ToString(); + fileName = newFilename; break; } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj index e85201d6165..e3dae6dda6b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj @@ -1397,6 +1397,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ComboBox.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ComboBox.cs index ad06fe9e8ce..6eea8bca056 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ComboBox.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ComboBox.cs @@ -726,7 +726,7 @@ private void TextUpdated(string newText, bool textBoxUpdated) if (ShouldPreserveUserEnteredPrefix) { // Retain the user entered prefix in the matched text. - matchedText = String.Concat(newText, matchedText.Substring(matchedTextInfo.MatchedPrefixLength)); + matchedText = String.Concat(newText, matchedText.AsSpan(matchedTextInfo.MatchedPrefixLength)); } // If there's an IME, do the replacement asynchronously so that diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridLengthConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridLengthConverter.cs index e19e6b4ca93..ad7a28268eb 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridLengthConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridLengthConverter.cs @@ -270,8 +270,8 @@ private static DataGridLength ConvertFromString(string s, CultureInfo cultureInf (unit == DataGridLengthUnitType.Pixel) || DoubleUtil.AreClose(unitFactor, 1.0), "unitFactor should not be other than 1.0 unless the unit type is Pixel."); - string valueString = goodString.Substring(0, strLen - strLenUnit); - value = Convert.ToDouble(valueString, cultureInfo) * unitFactor; + ReadOnlySpan valueString = goodString.AsSpan(0, strLen - strLenUnit); + value = double.Parse(valueString, provider: cultureInfo) * unitFactor; } return new DataGridLength(value, unit); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs index e322872890c..77e6cf49431 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs @@ -1130,9 +1130,9 @@ void FormatCollectionChangedSource(int level, object source, bool? isLikely, Lis int index = aqn.LastIndexOf(PublicKeyToken); if (index >= 0) { - string token = aqn.Substring(index + PublicKeyToken.Length); - if (String.Compare(token, MS.Internal.PresentationFramework.BuildInfo.WCP_PUBLIC_KEY_TOKEN, StringComparison.OrdinalIgnoreCase) == 0 || - String.Compare(token, MS.Internal.PresentationFramework.BuildInfo.DEVDIV_PUBLIC_KEY_TOKEN, StringComparison.OrdinalIgnoreCase) == 0) + ReadOnlySpan token = aqn.AsSpan(index + PublicKeyToken.Length); + if (token.Equals(MS.Internal.PresentationFramework.BuildInfo.WCP_PUBLIC_KEY_TOKEN, StringComparison.OrdinalIgnoreCase) || + token.Equals(MS.Internal.PresentationFramework.BuildInfo.DEVDIV_PUBLIC_KEY_TOKEN, StringComparison.OrdinalIgnoreCase)) { isLikely = false; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextSearch.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextSearch.cs index 2c18a37e20b..d82cb41822b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextSearch.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextSearch.cs @@ -335,15 +335,17 @@ private static void GetMatchingPrefixAndRemainingTextLength(string matchedText, // mostly compression or expansion is not involved. So start with length of newText int i = newText.Length; int j = i + 1; - + + CompareInfo compareInfo = (cultureInfo ?? CultureInfo.CurrentCulture).CompareInfo; + CompareOptions options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; do { - string temp; + ReadOnlySpan temp; if (i >= 1) { - temp = matchedText.Substring(0, i); - if (String.Compare(newText, temp, ignoreCase, cultureInfo) == 0) + temp = matchedText.AsSpan(0, i); + if (compareInfo.Compare(newText, temp, options) == 0) { matchedPrefixLength = i; textExcludingPrefixLength = matchedText.Length - i; @@ -352,8 +354,8 @@ private static void GetMatchingPrefixAndRemainingTextLength(string matchedText, } if (j <= matchedText.Length) { - temp = matchedText.Substring(0, j); - if (String.Compare(newText, temp, ignoreCase, cultureInfo) == 0) + temp = matchedText.AsSpan(0, j); + if (compareInfo.Compare(newText, temp, options) == 0) { matchedPrefixLength = j; textExcludingPrefixLength = matchedText.Length - j; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs index 32d2b6da13b..1e989190c56 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs @@ -12217,11 +12217,11 @@ private static string DisplayType(object o) sb.Append("/"); } - string name = t.ToString(); + ReadOnlySpan name = t.ToString(); isWPFControl = name.StartsWith("System.Windows.Controls."); if (isWPFControl) { - name = name.Substring(24); // 24 == length of "s.w.c." + name = name.Slice(24); // 24 == length of "s.w.c." } sb.Append(name); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSOMTextRun.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSOMTextRun.cs index 724bcada810..a2df2d8cd73 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSOMTextRun.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSOMTextRun.cs @@ -153,13 +153,14 @@ public static FixedSOMTextRun Create(Rect boundingRect, GeneralTransform transfo && String.IsNullOrEmpty(glyphs.CaretStops) && FixedTextBuilder.MostlyRTL(s)) { - char[] chars = new char[run.Text.Length]; - for (int i=0; i + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = runText[runText.Length - 1 - i]; + } + }); } if (s == "" && glyphs.Indices != null && glyphs.Indices.Length > 0) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSchema.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSchema.cs index a57e90ce3a8..c894c5a6c49 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSchema.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/FixedSchema.cs @@ -441,15 +441,14 @@ public override string[] ExtractUriFromAttr(string attrName, string attrValue) attrName.Equals("Fill", StringComparison.Ordinal) || attrName.Equals("Stroke", StringComparison.Ordinal)) { - attrValue = attrValue.Trim(); - if (attrValue.StartsWith(_contextColor, StringComparison.Ordinal)) + ReadOnlySpan attrValueSpan = attrValue.AsSpan().Trim(); + if (attrValueSpan.StartsWith(_contextColor, StringComparison.Ordinal)) { - attrValue = attrValue.Substring(_contextColor.Length); - attrValue = attrValue.Trim(); - string[] tokens = attrValue.Split(new char[] { ' ' }); - if (tokens.GetLength(0) >= 1) + attrValueSpan = attrValueSpan.Slice(_contextColor.Length).Trim(); + int spacePos = attrValueSpan.IndexOf(' '); + if (spacePos >= 0) { - return new string[] { tokens[0] }; + return new string[] { attrValueSpan.Slice(0, spacePos).ToString() }; } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs index 99af3a0f74d..966cf80b449 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs @@ -232,14 +232,14 @@ internal static long PxToHalfPointRounded(double px) } } - internal static bool StringToDouble(string s, ref double d) + internal static bool StringToDouble(ReadOnlySpan s, ref double d) { bool ret = true; d = 0.0; try { - d = System.Convert.ToDouble(s, CultureInfo.InvariantCulture); + d = double.Parse(s, provider: CultureInfo.InvariantCulture); } catch (System.OverflowException) { @@ -253,14 +253,14 @@ internal static bool StringToDouble(string s, ref double d) return ret; } - internal static bool StringToInt(string s, ref int i) + internal static bool StringToInt(ReadOnlySpan s, ref int i) { bool ret = true; i = 0; try { - i = System.Convert.ToInt32(s, CultureInfo.InvariantCulture); + i = int.Parse(s, provider: CultureInfo.InvariantCulture); } catch (System.OverflowException) { @@ -297,7 +297,7 @@ internal static string StringToXMLAttribute(string s) return sb.ToString(); } - internal static bool HexStringToInt(string s, ref int i) + internal static bool HexStringToInt(ReadOnlySpan s, ref int i) { bool ret = true; @@ -605,7 +605,6 @@ private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, int toThe3 = 17576; int toThe4 = 456976; - char[] ca = new char[1]; int temp; temp = 0; @@ -617,8 +616,7 @@ private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, if (temp > 0) { if (temp > 26) temp = 26; - ca[0] = (char)('A' + (temp - 1)); - sb.Append(ca); + sb.Append((char)('A' + (temp - 1))); } temp = 0; @@ -629,8 +627,7 @@ private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, } if (temp > 0) { - ca[0] = (char)('A' + (temp - 1)); - sb.Append(ca); + sb.Append((char)('A' + (temp - 1))); } temp = 0; @@ -641,8 +638,7 @@ private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, } if (temp > 0) { - ca[0] = (char)('A' + (temp - 1)); - sb.Append(ca); + sb.Append((char)('A' + (temp - 1))); } temp = 0; @@ -653,12 +649,10 @@ private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, } if (temp > 0) { - ca[0] = (char)('A' + (temp - 1)); - sb.Append(ca); + sb.Append((char)('A' + (temp - 1))); } - ca[0] = (char)('A' + (nCount - 1)); - sb.Append(ca); + sb.Append((char)('A' + (nCount - 1))); if (ms == MarkerStyle.MarkerUpperAlpha) { @@ -3803,8 +3797,8 @@ internal Hashtable FontMappings { if (lhs_name.Length > rhs_name.Length) { - string s = lhs_name.Substring(0, rhs_name.Length); - if (string.Compare(s, rhs_name, StringComparison.OrdinalIgnoreCase) == 0) + ReadOnlySpan s = lhs_name.AsSpan(0, rhs_name.Length); + if (s.Equals(rhs_name, StringComparison.OrdinalIgnoreCase)) { bAdd = true; } @@ -5038,7 +5032,7 @@ internal void AppendXamlEncoded(string text) } if (currentIndex != index) { - string substring = text.Substring(index, currentIndex - index); + ReadOnlySpan substring = text.AsSpan(index, currentIndex - index); xamlStringBuilder.Append(substring); } if (currentIndex < text.Length) @@ -8632,7 +8626,7 @@ private void ProcessSymbolFieldInstruction(DocumentNode dn, string instr, ref in { continue; } - string ptString = instr.Substring(iStart, i - iStart); + ReadOnlySpan ptString = instr.AsSpan(iStart, i - iStart); // Now convert number part bool ret = true; @@ -8640,7 +8634,7 @@ private void ProcessSymbolFieldInstruction(DocumentNode dn, string instr, ref in try { - d = System.Convert.ToDouble(ptString, CultureInfo.InvariantCulture); + d = double.Parse(ptString, provider: CultureInfo.InvariantCulture); } catch (System.OverflowException) { @@ -8834,10 +8828,7 @@ private void ConvertSymbolCharValueToText(DocumentNode dn, int nChar, EncodeType case EncodeType.Unicode: if (nChar < 0xFFFF) { - char[] unicodeChar = new char[1]; - - unicodeChar[0] = (char)nChar; - dn.AppendXamlEncoded(new string(unicodeChar)); + dn.AppendXamlEncoded(new string(stackalloc char[1] { (char)nChar })); } break; @@ -11412,12 +11403,7 @@ internal void HandleCodePageTokens(RtfToken token, FormatState formatState) formatState.RtfDestination = RtfDestination.DestUPR; break; case RtfControlWord.Ctrl_U: - { - char[] unicodeChar = new char[1]; - - unicodeChar[0] = (char)token.Parameter; - ProcessText(new string(unicodeChar)); - } + ProcessText(new string(stackalloc char[1] { (char)token.Parameter })); break; case RtfControlWord.Ctrl_UD: { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs index 5bf5bb768e1..234b8e4b5f2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs @@ -2737,14 +2737,11 @@ XamlToRtfError IXamlContentHandler.SkippedEntity(string name) xamlToRtfError = XamlToRtfError.InvalidFormat; if (name.Length >= 5) { - string num = name.Substring(3, name.Length - 4); int i = 0; - bool ret = Converters.HexStringToInt(num, ref i); + bool ret = Converters.HexStringToInt(name.AsSpan(3, name.Length - 4), ref i); if (i >= 0 && i <= 0xFFFF) { - char[] ac = new char[1]; - ac[0] = (char)i; - string s = new string(ac); + string s = new string(stackalloc char[1] { (char)i }); return ((IXamlContentHandler)this).Characters(s); } } @@ -2753,14 +2750,12 @@ XamlToRtfError IXamlContentHandler.SkippedEntity(string name) { if (name.Length >= 4) { - string num = name.Substring(2, name.Length - 3); + ReadOnlySpan num = name.Substring(2, name.Length - 3); int i = 0; bool ret = Converters.StringToInt(num, ref i); if (i >= 0 && i <= 0xFFFF) { - char[] ac = new char[1]; - ac[0] = (char)i; - string s = new string(ac); + string s = new string(stackalloc char[1] { (char)i }); return ((IXamlContentHandler)this).Characters(s); } } @@ -3547,7 +3542,7 @@ internal static bool ConvertToFont(ConverterState converterState, string attribu return true; } - internal static bool ConvertToFontSize(ConverterState converterState, string s, ref double d) + internal static bool ConvertToFontSize(ConverterState converterState, ReadOnlySpan s, ref double d) { if (s.Length == 0) { @@ -3561,11 +3556,11 @@ internal static bool ConvertToFontSize(ConverterState converterState, string s, n--; } - string units = null; + ReadOnlySpan units = default; if (n < s.Length - 1) { - units = s.Substring(n + 1); - s = s.Substring(0, n + 1); + units = s.Slice(n + 1); + s = s.Slice(0, n + 1); } // Now convert number part @@ -3574,7 +3569,7 @@ internal static bool ConvertToFontSize(ConverterState converterState, string s, if (ret) { // No units mean pixels - if (units == null || units.Length == 0) + if (units.IsEmpty) { d = Converters.PxToPt(d); } @@ -3813,7 +3808,7 @@ internal static bool ConvertToStartIndex(ConverterState converterState, string s return ret; } - internal static bool ConvertToThickness(ConverterState converterState, string thickness, ref XamlThickness xthickness) + internal static bool ConvertToThickness(ConverterState converterState, ReadOnlySpan thickness, ref XamlThickness xthickness) { int numints = 0; int s = 0; @@ -3827,7 +3822,7 @@ internal static bool ConvertToThickness(ConverterState converterState, string th e++; } - string onenum = thickness.Substring(s, e - s); + ReadOnlySpan onenum = thickness.Slice(s, e - s); if (onenum.Length > 0) { double d = 0.0f; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs index c3fa3128d40..e115114fa41 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs @@ -386,7 +386,7 @@ private void ParseGlyphRunProperties() _glyphRunProperties = glyphRunProperties; } - private static bool IsEmpty(string s) + private static bool IsEmpty(ReadOnlySpan s) { foreach (char c in s) { @@ -406,14 +406,14 @@ private static bool IsEmpty(string s) /// /// true if glyph index is present, false if glyph index is not present. private bool ReadGlyphIndex( - string valueSpec, + ReadOnlySpan valueSpec, ref bool inCluster, ref int glyphClusterSize, ref int characterClusterSize, ref ushort glyphIndex) { // the format is ... [(CharacterClusterSize[:GlyphClusterSize])] GlyphIndex ... - string glyphIndexString = valueSpec; + ReadOnlySpan glyphIndexString = valueSpec; int firstBracket = valueSpec.IndexOf('('); if (firstBracket != -1) @@ -437,26 +437,26 @@ private bool ReadGlyphIndex( if (colon == -1) { // parse glyph cluster size - string characterClusterSpec = valueSpec.Substring(firstBracket + 1, secondBracket - (firstBracket + 1)); - characterClusterSize = int.Parse(characterClusterSpec, CultureInfo.InvariantCulture); + ReadOnlySpan characterClusterSpec = valueSpec.Slice(firstBracket + 1, secondBracket - (firstBracket + 1)); + characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture); glyphClusterSize = 1; } else { if (colon <= firstBracket + 1 || colon >= secondBracket - 1) throw new ArgumentException(SR.Get(SRID.GlyphsClusterMisplacedSeparator)); - string characterClusterSpec = valueSpec.Substring(firstBracket + 1, colon - (firstBracket + 1)); - characterClusterSize = int.Parse(characterClusterSpec, CultureInfo.InvariantCulture); - string glyphClusterSpec = valueSpec.Substring(colon + 1, secondBracket - (colon + 1)); - glyphClusterSize = int.Parse(glyphClusterSpec, CultureInfo.InvariantCulture); + ReadOnlySpan characterClusterSpec = valueSpec.Slice(firstBracket + 1, colon - (firstBracket + 1)); + characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture); + ReadOnlySpan glyphClusterSpec = valueSpec.Slice(colon + 1, secondBracket - (colon + 1)); + glyphClusterSize = int.Parse(glyphClusterSpec, provider: CultureInfo.InvariantCulture); } inCluster = true; - glyphIndexString = valueSpec.Substring(secondBracket + 1); + glyphIndexString = valueSpec.Slice(secondBracket + 1); } if (IsEmpty(glyphIndexString)) return false; - glyphIndex = ushort.Parse(glyphIndexString, CultureInfo.InvariantCulture); + glyphIndex = ushort.Parse(glyphIndexString, provider: CultureInfo.InvariantCulture); return true; } @@ -564,7 +564,7 @@ private int ParseGlyphsProperty( { int len = i - valueStartIndex; - string valueSpec = glyphsProp.Substring(valueStartIndex, len); + ReadOnlySpan valueSpec = glyphsProp.AsSpan(valueStartIndex, len); #region Interpret one comma-delimited value @@ -611,7 +611,7 @@ private int ParseGlyphsProperty( // interpret glyph advance spec if (!IsEmpty(valueSpec)) { - parsedGlyphData.advanceWidth = double.Parse(valueSpec, CultureInfo.InvariantCulture); + parsedGlyphData.advanceWidth = double.Parse(valueSpec, provider: CultureInfo.InvariantCulture); if (parsedGlyphData.advanceWidth < 0) throw new ArgumentException(SR.Get(SRID.GlyphsAdvanceWidthCannotBeNegative)); } @@ -620,13 +620,13 @@ private int ParseGlyphsProperty( case 2: // interpret glyph offset X if (!IsEmpty(valueSpec)) - parsedGlyphData.offsetX = double.Parse(valueSpec, CultureInfo.InvariantCulture); + parsedGlyphData.offsetX = double.Parse(valueSpec, provider: CultureInfo.InvariantCulture); break; case 3: // interpret glyph offset Y if (!IsEmpty(valueSpec)) - parsedGlyphData.offsetY = double.Parse(valueSpec, CultureInfo.InvariantCulture); + parsedGlyphData.offsetY = double.Parse(valueSpec, provider: CultureInfo.InvariantCulture); break; default: diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/Baml2006Reader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/Baml2006Reader.cs index 10b3e924377..e55260737de 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/Baml2006Reader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/Baml2006Reader.cs @@ -2068,11 +2068,10 @@ private string Logic_GetFullXmlns(string uriInput) int colonIdx = uriInput.IndexOf(':'); if (colonIdx != -1) { - string uriTypePrefix = uriInput.Substring(0, colonIdx); - if (String.Equals(uriTypePrefix, "clr-namespace")) + ReadOnlySpan uriTypePrefix = uriInput.AsSpan(0, colonIdx); + if (uriTypePrefix.Equals("clr-namespace", StringComparison.Ordinal)) { //We have a clr-namespace so do special processing - int clrNsStartIdx = colonIdx + 1; int semicolonIdx = uriInput.IndexOf(';'); if (-1 == semicolonIdx) { @@ -2090,13 +2089,13 @@ private string Logic_GetFullXmlns(string uriInput) { throw new ArgumentException(SR.Get(SRID.MissingTagInNamespace, "=", uriInput)); } - string keyword = uriInput.Substring(assemblyKeywordStartIdx, equalIdx - assemblyKeywordStartIdx); - if (!String.Equals(keyword, "assembly")) + ReadOnlySpan keyword = uriInput.AsSpan(assemblyKeywordStartIdx, equalIdx - assemblyKeywordStartIdx); + if (!keyword.Equals("assembly", StringComparison.Ordinal)) { throw new ArgumentException(SR.Get(SRID.AssemblyTagMissing, "assembly", uriInput)); } - string assemblyName = uriInput.Substring(equalIdx + 1); - if (String.IsNullOrEmpty(assemblyName)) + ReadOnlySpan assemblyName = uriInput.AsSpan(equalIdx + 1); + if (assemblyName.TrimStart().IsEmpty) { return uriInput + GetAssemblyNameForNamespace(_settings.LocalAssembly); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs index 2a900de2ae9..92c71ea55df 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs @@ -355,16 +355,16 @@ private string ConvertMarkupItemToString(MarkupObject item) Debug.Assert(!propertyWritten, "An argument was returned after a property was set. All arguments must be returned first and in order"); } - string value = property.StringValue; + ReadOnlySpan value = property.StringValue; - if (value != null && value.Length > 0) + if (value.Length > 0) { if (value[0] == '{') { if (value.Length > 1 && value[1] == '}') { // It is a literal quote, remove the literals and write the text with escapes. - value = value.Substring(2); + value = value.Slice(2); } else { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/MarkupWriter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/MarkupWriter.cs index 16be0678f53..3a6ba41674c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/MarkupWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/MarkupWriter.cs @@ -1649,13 +1649,13 @@ public static string GetDefaultPrefixFor(string uri) result = "assembly"; if (uri.StartsWith(clrUriPrefix, StringComparison.Ordinal)) { - string ns = uri.Substring(clrUriPrefix.Length, uri.IndexOf(';') - clrUriPrefix.Length); + ReadOnlySpan ns = uri.AsSpan(clrUriPrefix.Length, uri.IndexOf(';') - clrUriPrefix.Length); StringBuilder r = new StringBuilder(); for (int i = 0; i < ns.Length; i++) { char c = ns[i]; if (c >= 'A' && c <= 'Z') - r.Append(c.ToString().ToLower(CultureInfo.InvariantCulture)); + r.Append(char.ToLowerInvariant(c)); } if (r.Length > 0) result = r.ToString(); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlFigureLengthSerializer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlFigureLengthSerializer.cs index 3ad0264d81c..0d54f3b248f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlFigureLengthSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlFigureLengthSerializer.cs @@ -257,8 +257,8 @@ static internal void FromString( Debug.Assert( unit == FigureUnitType.Pixel || DoubleUtil.AreClose(unitFactor, 1.0) ); - string valueString = goodString.Substring(0, strLen - strLenUnit); - value = Convert.ToDouble(valueString, cultureInfo) * unitFactor; + ReadOnlySpan valueString = goodString.AsSpan(0, strLen - strLenUnit); + value = double.Parse(valueString, provider: cultureInfo) * unitFactor; } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlGridLengthSerializer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlGridLengthSerializer.cs index aebb66764a0..5618e49397e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlGridLengthSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlGridLengthSerializer.cs @@ -259,8 +259,8 @@ static internal void FromString( Debug.Assert( unit == GridUnitType.Pixel || DoubleUtil.AreClose(unitFactor, 1.0) ); - string valueString = goodString.Substring(0, strLen - strLenUnit); - value = Convert.ToDouble(valueString, cultureInfo) * unitFactor; + ReadOnlySpan valueString = goodString.AsSpan(0, strLen - strLenUnit); + value = double.Parse(valueString, provider: cultureInfo) * unitFactor; } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs index b08f19ed00f..6f864c6bbca 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs @@ -918,9 +918,10 @@ internal static bool IsPropertyReference(string name) // return true if the name has the form: (nnn) internal static bool IsParameterIndex(string name, out int index) { + ReadOnlySpan toParse; if (IsPropertyReference(name)) { - name = name.Substring(1, name.Length - 2); + toParse = name.AsSpan(1, name.Length - 2); } else { @@ -928,7 +929,7 @@ internal static bool IsParameterIndex(string name, out int index) return false; } - return Int32.TryParse( name, + return Int32.TryParse(toParse, NumberStyles.Integer, TypeConverterHelper.InvariantEnglishUS.NumberFormat, out index); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPathConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPathConverter.cs index f6655782847..9fff1d70809 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPathConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPathConverter.cs @@ -199,13 +199,13 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, } int index; - if (Int32.TryParse( originalPath.Substring(i+1, j-i-1), + if (Int32.TryParse( originalPath.AsSpan(i+1, j-i-1), NumberStyles.Integer, TypeConverterHelper.InvariantEnglishUS.NumberFormat, out index)) { // found (n). Write out the path so far, including the opening ( - builder.Append(originalPath.Substring(start, i-start+1)); + builder.Append(originalPath.AsSpan(start, i-start+1)); object pathPart = parameters[index]; @@ -306,7 +306,7 @@ public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, if (start < originalPath.Length) { - builder.Append(originalPath.Substring(start)); + builder.Append(originalPath.AsSpan(start)); } return builder.ToString(); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/documents/DocumentApplicationDocumentViewer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/documents/DocumentApplicationDocumentViewer.cs index b2962486502..138f8aa53cd 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/documents/DocumentApplicationDocumentViewer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationUI/MS/Internal/documents/DocumentApplicationDocumentViewer.cs @@ -1851,7 +1851,7 @@ private void AddZoomComboBoxItem(ZoomComboBoxItem zoomItem, String name) ZoomComboBox.Items.Add(newItem); } - private static bool StringToZoomValue(string zoomString, out double zoomValue) + private static bool StringToZoomValue(ReadOnlySpan zoomString, out double zoomValue) { bool isValidArg = false; zoomValue = 0.0; @@ -1862,7 +1862,7 @@ private static bool StringToZoomValue(string zoomString, out double zoomValue) try { // Remove whitespace on either end of the string. - if ((culture != null) && !String.IsNullOrEmpty(zoomString)) + if ((culture != null) && !zoomString.IsEmpty) { zoomString = zoomString.Trim(); @@ -1879,7 +1879,7 @@ private static bool StringToZoomValue(string zoomString, out double zoomValue) culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase)) { - zoomString = zoomString.Substring(0, zoomString.Length - 1); + zoomString = zoomString.Slice(0, zoomString.Length - 1); } break; case 2: // %n @@ -1889,14 +1889,14 @@ private static bool StringToZoomValue(string zoomString, out double zoomValue) culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase)) { - zoomString = zoomString.Substring(1); + zoomString = zoomString.Slice(1); } break; } } // If this conversion throws then the string wasn't a valid zoom value. - zoomValue = System.Convert.ToDouble(zoomString, culture); + zoomValue = double.Parse(zoomString, provider: culture); isValidArg = true; } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationUI/PresentationUI.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationUI/PresentationUI.csproj index 7516c9a4926..421b0514185 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationUI/PresentationUI.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationUI/PresentationUI.csproj @@ -244,6 +244,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Packaging/XpsFixedPageReaderWriter.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Packaging/XpsFixedPageReaderWriter.cs index 8f2daca4dfc..af81fd48535 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Packaging/XpsFixedPageReaderWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Packaging/XpsFixedPageReaderWriter.cs @@ -1866,26 +1866,24 @@ Uri resourceUri Uri imageUri ) { - //Extract file extension + //Extract file extension without '.' String path = imageUri.OriginalString; - String extension = Path.GetExtension(path).ToLower(CultureInfo.InvariantCulture); - //remove . - extension = extension.Substring(1); + ReadOnlySpan extension = Path.GetExtension(path).ToLower(CultureInfo.InvariantCulture).AsSpan(1); - ContentType contentType = null; - if (String.CompareOrdinal(extension, XpsS0Markup.JpgExtension) == 0) + ContentType contentType; + if (extension.Equals(XpsS0Markup.JpgExtension, StringComparison.Ordinal)) { contentType = XpsS0Markup.JpgContentType; } - else if (String.CompareOrdinal(extension, XpsS0Markup.PngExtension) == 0) + else if (extension.Equals(XpsS0Markup.PngExtension, StringComparison.Ordinal)) { contentType = XpsS0Markup.PngContentType; } - else if (String.CompareOrdinal(extension, XpsS0Markup.TifExtension) == 0) + else if (extension.Equals(XpsS0Markup.TifExtension, StringComparison.Ordinal)) { contentType = XpsS0Markup.TifContentType; } - else if (String.CompareOrdinal(extension, XpsS0Markup.WdpExtension) == 0) + else if (extension.Equals(XpsS0Markup.WdpExtension, StringComparison.Ordinal)) { contentType = XpsS0Markup.WdpContentType; } diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/ReachFramework.csproj b/src/Microsoft.DotNet.Wpf/src/ReachFramework/ReachFramework.csproj index c7ea5df69f3..0b5b5afd6a6 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/ReachFramework.csproj +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/ReachFramework.csproj @@ -350,6 +350,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/XpsFontSubsetter.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/XpsFontSubsetter.cs index 50fa6a1ead1..a333e98e213 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/XpsFontSubsetter.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/XpsFontSubsetter.cs @@ -698,23 +698,19 @@ Stream stream void ObfuscateData( byte[] fontData, Guid guid ) { - byte[] guidByteArray = new byte[16]; - // Convert the GUID into string in 32 digits format (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) + // Convert the GUID into string in 32 digits format (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) + Span guidByteArray = stackalloc byte[16]; string guidString = guid.ToString("N"); - for (int i = 0; i < guidByteArray.Length; i++) { - guidByteArray[i] = Convert.ToByte(guidString.Substring(i * 2, 2), 16); - } - - for( int j = 0; j < 2; j++ ) { - for( int i = 0; i < 16; i ++ ) { + for( int i = 0; i < 16; i ++ ) + { fontData[i+j*16] ^= guidByteArray[15-i]; } } diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializer.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializer.cs index 14c134a1bd9..83c6e68732e 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializer.cs @@ -197,13 +197,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializerAsync.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializerAsync.cs index f0e09a3423c..1f1225bbd6f 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializerAsync.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachDocumentSequenceSerializerAsync.cs @@ -235,13 +235,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + ")"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializer.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializer.cs index 889827ed837..a85bd29b31b 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializer.cs @@ -280,13 +280,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializerAsync.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializerAsync.cs index 8126754539f..477f4cc6198 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializerAsync.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedDocumentSerializerAsync.cs @@ -320,13 +320,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializer.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializer.cs index 1bc86918c07..76d6e3c1413 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializer.cs @@ -353,13 +353,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializerAsync.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializerAsync.cs index d837b3efbb9..186f5d0bee0 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializerAsync.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/ReachFixedPageSerializerAsync.cs @@ -325,13 +325,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/XpsOMFixedPageSerializer.cs b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/XpsOMFixedPageSerializer.cs index 18fa49f9eed..bf5204f9bfd 100644 --- a/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/XpsOMFixedPageSerializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/ReachFramework/Serialization/manager/XpsOMFixedPageSerializer.cs @@ -311,13 +311,10 @@ SerializablePropertyContext serializablePropertyContext if (typeof(Type).IsInstanceOfType(propertyValue)) { int index = valueAsString.LastIndexOf('.'); - - if (index > 0) - { - valueAsString = valueAsString.Substring(index + 1); - } - - valueAsString = XpsSerializationManager.TypeOfString + valueAsString + "}"; + valueAsString = string.Concat( + XpsSerializationManager.TypeOfString, + index > 0 ? valueAsString.AsSpan(index + 1) : valueAsString, + "}"); } } else diff --git a/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/Microsoft/Windows/Controls/Ribbon/RibbonControlLengthConverter.cs b/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/Microsoft/Windows/Controls/Ribbon/RibbonControlLengthConverter.cs index b7d0b90dbe6..8dcd365c336 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/Microsoft/Windows/Controls/Ribbon/RibbonControlLengthConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/Microsoft/Windows/Controls/Ribbon/RibbonControlLengthConverter.cs @@ -238,8 +238,8 @@ internal static RibbonControlLength FromString(string s, CultureInfo cultureInfo Debug.Assert(unit == RibbonControlLengthUnitType.Pixel || unit == RibbonControlLengthUnitType.Item || DoubleUtil.AreClose(unitFactor, 1.0)); - string valueString = goodString.Substring(0, strLen - strLenUnit); - value = Convert.ToDouble(valueString, cultureInfo) * unitFactor; + ReadOnlySpan valueString = goodString.AsSpan(0, strLen - strLenUnit); + value = double.Parse(valueString, provider: cultureInfo) * unitFactor; } return new RibbonControlLength(value, unit); diff --git a/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/System.Windows.Controls.Ribbon.csproj b/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/System.Windows.Controls.Ribbon.csproj index f2fa5e8c3f1..aaa9b1a98dd 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/System.Windows.Controls.Ribbon.csproj +++ b/src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/System.Windows.Controls.Ribbon.csproj @@ -206,6 +206,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System.Xaml.csproj b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System.Xaml.csproj index 31f9260cad2..9c20c463441 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System.Xaml.csproj +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System.Xaml.csproj @@ -100,6 +100,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/KnownStrings.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/KnownStrings.cs index c3d6341f5ac..e18d473c6d2 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/KnownStrings.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/KnownStrings.cs @@ -62,6 +62,11 @@ public static bool Eq(string a, string b) return string.Equals(a, b, StringComparison.Ordinal); } + public static bool Eq(ReadOnlySpan a, ReadOnlySpan b) + { + return a.Equals(b, StringComparison.Ordinal); + } + /// /// Standard String Index search operation. /// diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/ClrNamespaceUriParser.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/ClrNamespaceUriParser.cs index b5e1994cf91..aa65e5a1c49 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/ClrNamespaceUriParser.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/ClrNamespaceUriParser.cs @@ -29,7 +29,7 @@ public static bool TryParseUri(string uriInput, out string clrNs, out string ass return false; } - string keyword = uriInput.Substring(0, colonIdx); + ReadOnlySpan keyword = uriInput.AsSpan(0, colonIdx); if (!KS.Eq(keyword, KnownStrings.UriClrNamespace)) { return false; @@ -56,7 +56,7 @@ public static bool TryParseUri(string uriInput, out string clrNs, out string ass return false; } - keyword = uriInput.Substring(assemblyKeywordStartIdx, equalIdx - assemblyKeywordStartIdx); + keyword = uriInput.AsSpan(assemblyKeywordStartIdx, equalIdx - assemblyKeywordStartIdx); if (!KS.Eq(keyword, KnownStrings.UriAssembly)) { return false; diff --git a/src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WordBreaker.cs b/src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WordBreaker.cs index d4e152a2662..df670d19dae 100644 --- a/src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WordBreaker.cs +++ b/src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WordBreaker.cs @@ -158,7 +158,7 @@ public TextSymbolType GetSymbolType(LogicalDirection direction) TextSymbolType.Character; } - public int GetText(LogicalDirection direction, int maxLength, TextPosition limit, char[] chars, int startIndex) + public int GetText(LogicalDirection direction, int maxLength, TextPosition limit, Span chars, int startIndex) { // simplifying assumptions based on usage by word breaker. Debug.Assert(direction == LogicalDirection.Forward); @@ -728,7 +728,7 @@ internal static string GenerateText(TextPosition begin, TextPosition end) StringBuilder output = new StringBuilder(); TextNavigator navigator = begin.CreateNavigator(); TextSymbolType type; - char[] buffer = new char[1]; + Span buffer = stackalloc char[1]; char ch; if (begin.TextContainer != end.TextContainer) From 29d01b54e44047d5a5bf1b4e57be106bbbef40d3 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 28 Jun 2021 20:09:20 -0400 Subject: [PATCH 2/2] Address PR feedback --- .../Windows/Media/Animation/KeyTimeConverter.cs | 12 +++--------- .../System/Windows/Documents/RtfToXamlReader.cs | 4 ++-- .../System/Windows/Documents/XamlToRtfWriter.cs | 6 +++--- .../System/Windows/Documents/glyphs.cs | 8 ++++---- .../Primitives/ExtensionSimplifierMarkupObject.cs | 2 +- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs index 6819fa6271c..7b1d87f101d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/KeyTimeConverter.cs @@ -19,12 +19,6 @@ namespace System.Windows /// public class KeyTimeConverter : TypeConverter { - #region Data - - private static char[] _percentCharacter = new char[] { '%' }; - - #endregion - /// /// Returns whether or not this class can convert from a given type /// to an instance of a KeyTime. @@ -88,9 +82,9 @@ public override object ConvertFrom( { return KeyTime.Paced; } - else if (stringValue[stringValue.Length - 1] == _percentCharacter[0]) + else if (stringValue[stringValue.Length - 1] == '%') { - stringValue = stringValue.TrimEnd(_percentCharacter); + stringValue = stringValue.TrimEnd('%'); double doubleValue = (double)TypeDescriptor.GetConverter( typeof(double)).ConvertFrom( @@ -195,7 +189,7 @@ public override object ConvertTo( keyTime.Percent * 100.0, destinationType); - return string.Concat(returnValue, (ReadOnlySpan)_percentCharacter); + return string.Concat(returnValue, (ReadOnlySpan)stackalloc char[] { '%' }); case KeyTimeType.TimeSpan: diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs index 966cf80b449..977913889d4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/RtfToXamlReader.cs @@ -8828,7 +8828,7 @@ private void ConvertSymbolCharValueToText(DocumentNode dn, int nChar, EncodeType case EncodeType.Unicode: if (nChar < 0xFFFF) { - dn.AppendXamlEncoded(new string(stackalloc char[1] { (char)nChar })); + dn.AppendXamlEncoded(char.ToString((char)nChar)); } break; @@ -11403,7 +11403,7 @@ internal void HandleCodePageTokens(RtfToken token, FormatState formatState) formatState.RtfDestination = RtfDestination.DestUPR; break; case RtfControlWord.Ctrl_U: - ProcessText(new string(stackalloc char[1] { (char)token.Parameter })); + ProcessText(char.ToString((char)token.Parameter)); break; case RtfControlWord.Ctrl_UD: { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs index 234b8e4b5f2..38f25f977fe 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/XamlToRtfWriter.cs @@ -2741,7 +2741,7 @@ XamlToRtfError IXamlContentHandler.SkippedEntity(string name) bool ret = Converters.HexStringToInt(name.AsSpan(3, name.Length - 4), ref i); if (i >= 0 && i <= 0xFFFF) { - string s = new string(stackalloc char[1] { (char)i }); + string s = char.ToString((char)i); return ((IXamlContentHandler)this).Characters(s); } } @@ -2750,12 +2750,12 @@ XamlToRtfError IXamlContentHandler.SkippedEntity(string name) { if (name.Length >= 4) { - ReadOnlySpan num = name.Substring(2, name.Length - 3); + ReadOnlySpan num = name.AsSpan(2, name.Length - 3); int i = 0; bool ret = Converters.StringToInt(num, ref i); if (i >= 0 && i <= 0xFFFF) { - string s = new string(stackalloc char[1] { (char)i }); + string s = char.ToString((char)i); return ((IXamlContentHandler)this).Characters(s); } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs index e115114fa41..92d2546b2af 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/glyphs.cs @@ -407,10 +407,10 @@ private static bool IsEmpty(ReadOnlySpan s) /// true if glyph index is present, false if glyph index is not present. private bool ReadGlyphIndex( ReadOnlySpan valueSpec, - ref bool inCluster, - ref int glyphClusterSize, - ref int characterClusterSize, - ref ushort glyphIndex) + ref bool inCluster, + ref int glyphClusterSize, + ref int characterClusterSize, + ref ushort glyphIndex) { // the format is ... [(CharacterClusterSize[:GlyphClusterSize])] GlyphIndex ... ReadOnlySpan glyphIndexString = valueSpec; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs index 92c71ea55df..657b8e473cc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/ExtensionSimplifierMarkupObject.cs @@ -357,7 +357,7 @@ private string ConvertMarkupItemToString(MarkupObject item) ReadOnlySpan value = property.StringValue; - if (value.Length > 0) + if (!value.IsEmpty) { if (value[0] == '{') {