dotnet/wpf · error · ArgumentException

SR.CharacterMetrics_NegativeHorizontalAdvance

Error message

SR.CharacterMetrics_NegativeHorizontalAdvance

What it means

The CharacterMetrics(string) constructor parses a composite-font metrics string and computes horizontalAdvance = BlackBoxWidth + LeftSideBearing + RightSideBearing. A negative total is geometrically meaningless, so the constructor throws ArgumentException with SR.CharacterMetrics_NegativeHorizontalAdvance.

Solutions

  1. Correct the metrics string so BlackBoxWidth + LeftSideBearing + RightSideBearing >= 0.
  2. Clamp side bearings in the source data before constructing CharacterMetrics.
  3. Validate the composite font section with CompositeFontParser before use.

Example fix

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

// after
var parts = Parse(str);
if (parts.BlackBoxWidth + parts.LeftSideBearing + parts.RightSideBearing < 0)
    parts.LeftSideBearing = 0;
var m = new CharacterMetrics(Format(parts));
Defensive patterns

Strategy: validation

Validate before calling

static bool HasValidHorizontalAdvance(double blackBoxWidth, double left, double right)
    => blackBoxWidth + left + right >= 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 metrics string whose BlackBoxWidth plus side bearings sums to a negative number, e.g. a huge negative left/right side bearing exceeding the black-box width.

Common situations: Hand-edited or corrupted DeviceFont/CompositeFont .ini metric files; font vendor data with sign errors; parsing malformed embedded font metadata.

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/5778cfd1f432a682. Report an issue: GitHub.

Appendix: source

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

            set
            {
                double[] metrics = ParseMetrics(value);

                // Validate all the values before we assign to any field.
                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];
            }
        }

View on GitHub (pinned to 81131a70a4)