bool AddAdornment(AdornmentTagInfo adornmentInfo, HexViewLine line)
        {
            SizeChangedEventHandler sizeChanged = (a, e) => {
                var bounds = line.GetAdornmentBounds(adornmentInfo);
                if (bounds == null)
                {
                    return;
                }
                // Sometimes the size just gets changed very little, eg. from 400 to 399.95.....
                const double d = 0.5;
                if (e.NewSize.Height <= bounds.Value.Height + d && e.NewSize.Width <= bounds.Value.Width + d)
                {
                    return;
                }
                tagger?.RefreshSpans(new HexBufferSpanEventArgs(adornmentInfo.BufferSpan));
            };

            adornmentInfo.TopUIElement.SizeChanged += sizeChanged;

            VSTE.AdornmentRemovedCallback removedCallback = (a, b) => {
                adornmentTagInfos.Remove(adornmentInfo);
                adornmentInfo.TopUIElement.SizeChanged -= sizeChanged;
                adornmentInfo.TopUIElement.OnRemoved();
                if (adornmentInfo.HexTagSpan != null)
                {
                    adornmentInfo.HexTagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.HexTagSpan, b);
                }
                else
                {
                    adornmentInfo.HexTextTagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.HexTextTagSpan, b);
                }
            };

            Debug.Assert(!adornmentTagInfos.Contains(adornmentInfo));
            adornmentTagInfos.Add(adornmentInfo);
            // Use OwnerControlled because there are corner cases that the adornment layer can't handle,
            // eg. an adornment with buffer span length == 0 that is shown on its own line (word wrap).
            bool added = layer.AddAdornment(VSTE.AdornmentPositioningBehavior.OwnerControlled, (HexBufferSpan?)null, adornmentInfo, adornmentInfo.TopUIElement, removedCallback);

            if (!added)
            {
                removedCallback(null, adornmentInfo.TopUIElement);
            }
            return(added);
        }
        bool AddAdornment(AdornmentTagInfo adornmentInfo)
        {
            var oldSize = adornmentInfo.TopUIElement.DesiredSize;
            SizeChangedEventHandler sizeChanged = (a, e) => {
                if (e.NewSize == oldSize)
                {
                    return;
                }
                // Sometimes the size just gets changed very little, eg. from 400 to 399.95.....
                const double d = 0.5;
                if (Math.Abs(e.NewSize.Height - oldSize.Height) < d && Math.Abs(e.NewSize.Width - oldSize.Width) < d)
                {
                    return;
                }
                oldSize = e.NewSize;
                tagger?.RefreshSpans(new SnapshotSpanEventArgs(adornmentInfo.Span));
            };

            adornmentInfo.TopUIElement.SizeChanged += sizeChanged;

            AdornmentRemovedCallback removedCallback = (a, b) => {
                adornmentTagInfos.Remove(adornmentInfo);
                adornmentInfo.TopUIElement.SizeChanged -= sizeChanged;
                adornmentInfo.TopUIElement.OnRemoved();
                adornmentInfo.TagSpan.Tag.RemovalCallback?.Invoke(adornmentInfo.TagSpan, b);
            };

            Debug.Assert(!adornmentTagInfos.Contains(adornmentInfo));
            adornmentTagInfos.Add(adornmentInfo);
            // Use OwnerControlled because there are corner cases that the adornment layer can't handle,
            // eg. an adornment with buffer span length == 0 that is shown on its own line (word wrap).
            bool added = layer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled, null, adornmentInfo, adornmentInfo.TopUIElement, removedCallback);

            if (!added)
            {
                removedCallback(null, adornmentInfo.TopUIElement);
            }
            return(added);
        }