dotnet/wpf · error · ArgumentException

SR.CharacterMetrics_NegativeVerticalAdvance

Error message

SR.CharacterMetrics_NegativeVerticalAdvance

What it means

CharacterMetrics' constructor also computes verticalAdvance = BlackBoxHeight + TopSideBearing + BottomSideBearing and throws ArgumentException (SR.CharacterMetrics_NegativeVerticalAdvance) when that sum is negative, since a glyph's vertical advance cannot be negative in this model.

Solutions

  1. Fix the metrics string so BlackBoxHeight + TopSideBearing + BottomSideBearing >= 0.
  2. Sanitize/clamp negative vertical bearings in the data source.
  3. Regenerate metrics from the actual font rather than editing them manually.

Example fix

// before
var m = new CharacterMetrics("0,0,0,10,-10,0"); // negative vertical advance

// after
var m = new CharacterMetrics("0,0,0,10,0,0");
Defensive patterns

Strategy: validation

Validate before calling

static bool HasValidVerticalAdvance(double blackBoxHeight, double top, double bottom)
    => blackBoxHeight + top + bottom >= 0;

Try / catch

try { var m = new CharacterMetrics(str); }
catch (ArgumentException ex) { Log(ex.Message); m = CharacterMetrics.Default; }

Prevention

When it happens

Trigger: Constructing CharacterMetrics from a string where BlackBoxHeight plus top/bottom side bearings totals below zero.

Common situations: Corrupt or hand-edited composite font metric sections; automated metric extraction writing negative heights; copy/paste sign errors in font metadata files.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/e0383f245cccfcba. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/CharacterMetrics.cs:110

                CompositeFontParser.VerifyNonNegativeMultiplierOfEm(nameof(BlackBoxWidth), ref metrics[(int)FieldIndex.BlackBoxWidth]);
                CompositeFontParser.VerifyNonNegativeMultiplierOfEm(nameof(BlackBoxHeight), ref metrics[(int)FieldIndex.BlackBoxHeight]);
                CompositeFontParser.VerifyMultiplierOfEm(nameof(Baseline), ref metrics[(int)FieldIndex.Baseline]);
                CompositeFontParser.VerifyMultiplierOfEm(nameof(LeftSideBearing), ref metrics[(int)FieldIndex.LeftSideBearing]);
                CompositeFontParser.VerifyMultiplierOfEm(nameof(RightSideBearing), ref metrics[(int)FieldIndex.RightSideBearing]);
                CompositeFontParser.VerifyMultiplierOfEm(nameof(TopSideBearing), ref metrics[(int)FieldIndex.TopSideBearing]);
                CompositeFontParser.VerifyMultiplierOfEm(nameof(BottomSideBearing), ref metrics[(int)FieldIndex.BottomSideBearing]);

                double horizontalAdvance = metrics[(int)FieldIndex.BlackBoxWidth]
                    + metrics[(int)FieldIndex.LeftSideBearing]
                    + metrics[(int)FieldIndex.RightSideBearing];
                if (horizontalAdvance < 0)
                    throw new ArgumentException(SR.CharacterMetrics_NegativeHorizontalAdvance);

                double verticalAdvance = metrics[(int)FieldIndex.BlackBoxHeight]
                    + metrics[(int)FieldIndex.TopSideBearing]
                    + metrics[(int)FieldIndex.BottomSideBearing];
                if (verticalAdvance < 0)
                    throw new ArgumentException(SR.CharacterMetrics_NegativeVerticalAdvance);

                // Set all the properties.
                _blackBoxWidth = metrics[(int)FieldIndex.BlackBoxWidth];
                _blackBoxHeight = metrics[(int)FieldIndex.BlackBoxHeight];
                _baseline = metrics[(int)FieldIndex.Baseline];
                _leftSideBearing = metrics[(int)FieldIndex.LeftSideBearing];
                _rightSideBearing = metrics[(int)FieldIndex.RightSideBearing];
                _topSideBearing = metrics[(int)FieldIndex.TopSideBearing];
                _bottomSideBearing = metrics[(int)FieldIndex.BottomSideBearing];
            }
        }

        private static void AppendField(double value, FieldIndex fieldIndex, ref int lastIndex, StringBuilder s)
        {
            if (value != 0)
            {
                s.Append(',', (int)fieldIndex - lastIndex);
                lastIndex = (int)fieldIndex;

View on GitHub (pinned to 81131a70a4)