REGRESSION (r226138): Selecting a line that ends with zero-width joiner (ZWJ) may...
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Jan 2018 19:17:30 +0000 (19:17 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Jan 2018 19:17:30 +0000 (19:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181993
<rdar://problem/36421080>

Reviewed by David Hyatt.

Source/WebCore:

Re-implement paint optimization that was inadvertently removed in r226138. This optimization
works around an issue where selecting the last printable character in a line that is followed
followed by a zero-width joiner transforms the selected character.

We need to fix <https://bugs.webkit.org/show_bug.cgi?id=181964> to improve the interaction
of selection and zero-width joiner characters. For now, re-implement a paint optimization
to perform a single paint operation when the style of the non-selected text is identical
to the style of the selected text.

Test: fast/text/mac/select-character-before-zero-width-joiner.html

* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::MarkerSubrangeStyle::areBackgroundMarkerSubrangeStylesEqual):
(WebCore::InlineTextBox::MarkerSubrangeStyle::areForegroundMarkerSubrangeStylesEqual):
(WebCore::InlineTextBox::MarkerSubrangeStyle::areDecorationMarkerSubrangeStylesEqual):
Add helper functions to determine when marker styles are identical. We make use of these
equality functions to coalesce adjacent subranges that have the same visual style and
hence reduce the number of drawing commands to paint all the subranges in a line.

(WebCore::InlineTextBox::paint): Coalesce subranges before painting.

(WebCore::InlineTextBox::subdivideAndResolveStyle): Split out the logic to coalesce
subranges with the same style into its own function InlineTextBox::coalesceAdjacentSubranges()
and kept this function focused on subdivision and style resolution. Manually compute
the frontmost subranges so that we can resolve style for each subrange with respect to
the correct base style. Formerly we always resolved style with respect the specified
base style. Now we resolve style with respect the previous frontmost subrange to ensure
styles cascade as expected. This change causes no visual difference now. Once we implement
<https://bugs.webkit.org/show_bug.cgi?id=175784> we will be able to test this change
with respect to selection of ::spelling-error/::grammar-error pseudo elements.

(WebCore::InlineTextBox::coalesceAdjacentSubranges): Extracted logic from InlineTextBox::subdivideAndResolveStyle().

(WebCore::InlineTextBox::MarkerSubrangeStyle::operator== const): Deleted.
(WebCore::InlineTextBox::MarkerSubrangeStyle::operator!= const): Deleted.
Comparing MarkerSubrangeStyle objects should be performed using the appropriate
are*MarkerSubrangeStylesEqual() non-member function.

* rendering/InlineTextBox.h:
* rendering/MarkerSubrange.cpp:
(WebCore::subdivide): Remove overlap strategy FrontmostWithLongestEffectiveRange
as this strategy is now implemented by InlineTextBox::subdivideAndResolveStyle() and
InlineTextBox::coalesceAdjacentSubranges() that compute the set of frontmost subranges and
coalesces adjacent subranges with the same style into the longest effective subrange,
respectively. Unlike WebCore::subdivide(), InlineTextBox knows what the base style should
be for the subranges and can more aggressively coalesce adjacent subranges of different
types that have the same visual style.
* rendering/MarkerSubrange.h:

Tools:

Remove unit test for overlap strategy FrontmostWithLongestEffectiveRange
as we no longer support this strategy.

* TestWebKitAPI/Tests/WebCore/MarkerSubrange.cpp:

LayoutTests:

Add a Mac-specific test to ensure that selecting the last visible character on a line
that ends with a zero-width joiner (ZWJ) does not cause a text transformation of the
selected character.

We need to fix <https://bugs.webkit.org/show_bug.cgi?id=181964> for this test to
pass on Mac.

* TestExpectations: Skip the test directory on non-Mac platforms.
* fast/text/mac/select-character-before-zero-width-joiner-expected.html: Added.
* fast/text/mac/select-character-before-zero-width-joiner.html: Added.
* platform/mac/TestExpectations: Mark the test directory as PASS on Mac so that we run
all containing tests. Mark the test as ImageOnlyFailure until we fix <https://bugs.webkit.org/show_bug.cgi?id=181964>.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227533 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/text/mac/select-character-before-zero-width-joiner-expected.html [new file with mode: 0644]
LayoutTests/fast/text/mac/select-character-before-zero-width-joiner.html [new file with mode: 0644]
LayoutTests/platform/mac/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/InlineTextBox.h
Source/WebCore/rendering/MarkerSubrange.cpp
Source/WebCore/rendering/MarkerSubrange.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebCore/MarkerSubrange.cpp

index c3318cb..70807ef 100644 (file)
@@ -1,3 +1,24 @@
+2018-01-24  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r226138): Selecting a line that ends with zero-width joiner (ZWJ) may cause text transformation
+        https://bugs.webkit.org/show_bug.cgi?id=181993
+        <rdar://problem/36421080>
+
+        Reviewed by David Hyatt.
+
+        Add a Mac-specific test to ensure that selecting the last visible character on a line
+        that ends with a zero-width joiner (ZWJ) does not cause a text transformation of the
+        selected character.
+
+        We need to fix <https://bugs.webkit.org/show_bug.cgi?id=181964> for this test to
+        pass on Mac.
+
+        * TestExpectations: Skip the test directory on non-Mac platforms.
+        * fast/text/mac/select-character-before-zero-width-joiner-expected.html: Added.
+        * fast/text/mac/select-character-before-zero-width-joiner.html: Added.
+        * platform/mac/TestExpectations: Mark the test directory as PASS on Mac so that we run
+        all containing tests. Mark the test as ImageOnlyFailure until we fix <https://bugs.webkit.org/show_bug.cgi?id=181964>.
+
 2018-01-24  Youenn Fablet  <youenn@apple.com>
 
         Fetch response should copy its url from the request if null
index 00829e6..c1b0d7b 100644 (file)
@@ -28,6 +28,7 @@ fast/events/ios [ Skip ]
 fast/events/touch/ios [ Skip ]
 fast/history/ios [ Skip ]
 fast/scrolling/ios [ Skip ]
+fast/text/mac [ Skip ]
 scrollingcoordinator/ios [ Skip ]
 fast/content-observation [ Skip ]
 media/mac [ Skip ]
diff --git a/LayoutTests/fast/text/mac/select-character-before-zero-width-joiner-expected.html b/LayoutTests/fast/text/mac/select-character-before-zero-width-joiner-expected.html
new file mode 100644 (file)
index 0000000..902aed1
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p id="text" style="font-family: -apple-system">12</p>
+<script>
+var text = document.getElementById("text").firstChild;
+getSelection().setBaseAndExtent(text, 1, text, 2);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/mac/select-character-before-zero-width-joiner.html b/LayoutTests/fast/text/mac/select-character-before-zero-width-joiner.html
new file mode 100644 (file)
index 0000000..fa2f3e8
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p id="text" style="font-family: -apple-system">12&zwj;</p>
+<script>
+var text = document.getElementById("text").firstChild;
+getSelection().setBaseAndExtent(text, 1, text, 2);
+</script>
+</body>
+</html>
index 6d984e8..80b94ab 100644 (file)
@@ -37,6 +37,9 @@ http/tests/gzip-content-encoding [ Pass ]
 # FIXME: Mark as Pass once the fix for <rdar://problem/33822249> ships.
 http/tests/xmlhttprequest/gzip-content-type-no-content-encoding.html [ Pass Failure ]
 
+fast/text/mac [ Pass ]
+webkit.org/b/181964 fast/text/mac/select-character-before-zero-width-joiner.html [ ImageOnlyFailure ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////
index 512dd83..e7a7479 100644 (file)
@@ -1,3 +1,60 @@
+2018-01-24  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r226138): Selecting a line that ends with zero-width joiner (ZWJ) may cause text transformation
+        https://bugs.webkit.org/show_bug.cgi?id=181993
+        <rdar://problem/36421080>
+
+        Reviewed by David Hyatt.
+
+        Re-implement paint optimization that was inadvertently removed in r226138. This optimization
+        works around an issue where selecting the last printable character in a line that is followed
+        followed by a zero-width joiner transforms the selected character.
+
+        We need to fix <https://bugs.webkit.org/show_bug.cgi?id=181964> to improve the interaction
+        of selection and zero-width joiner characters. For now, re-implement a paint optimization
+        to perform a single paint operation when the style of the non-selected text is identical
+        to the style of the selected text.
+
+        Test: fast/text/mac/select-character-before-zero-width-joiner.html
+
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::MarkerSubrangeStyle::areBackgroundMarkerSubrangeStylesEqual):
+        (WebCore::InlineTextBox::MarkerSubrangeStyle::areForegroundMarkerSubrangeStylesEqual):
+        (WebCore::InlineTextBox::MarkerSubrangeStyle::areDecorationMarkerSubrangeStylesEqual):
+        Add helper functions to determine when marker styles are identical. We make use of these
+        equality functions to coalesce adjacent subranges that have the same visual style and
+        hence reduce the number of drawing commands to paint all the subranges in a line.
+        (WebCore::InlineTextBox::paint): Coalesce subranges before painting.
+
+        (WebCore::InlineTextBox::subdivideAndResolveStyle): Split out the logic to coalesce
+        subranges with the same style into its own function InlineTextBox::coalesceAdjacentSubranges()
+        and kept this function focused on subdivision and style resolution. Manually compute
+        the frontmost subranges so that we can resolve style for each subrange with respect to
+        the correct base style. Formerly we always resolved style with respect the specified
+        base style. Now we resolve style with respect the previous frontmost subrange to ensure
+        styles cascade as expected. This change causes no visual difference now. Once we implement
+        <https://bugs.webkit.org/show_bug.cgi?id=175784> we will be able to test this change
+        with respect to selection of ::spelling-error/::grammar-error pseudo elements.
+
+        (WebCore::InlineTextBox::coalesceAdjacentSubranges): Extracted logic from InlineTextBox::subdivideAndResolveStyle().
+
+        (WebCore::InlineTextBox::MarkerSubrangeStyle::operator== const): Deleted.
+        (WebCore::InlineTextBox::MarkerSubrangeStyle::operator!= const): Deleted.
+        Comparing MarkerSubrangeStyle objects should be performed using the appropriate
+        are*MarkerSubrangeStylesEqual() non-member function.
+
+        * rendering/InlineTextBox.h:
+        * rendering/MarkerSubrange.cpp:
+        (WebCore::subdivide): Remove overlap strategy FrontmostWithLongestEffectiveRange
+        as this strategy is now implemented by InlineTextBox::subdivideAndResolveStyle() and
+        InlineTextBox::coalesceAdjacentSubranges() that compute the set of frontmost subranges and
+        coalesces adjacent subranges with the same style into the longest effective subrange,
+        respectively. Unlike WebCore::subdivide(), InlineTextBox knows what the base style should
+        be for the subranges and can more aggressively coalesce adjacent subranges of different
+        types that have the same visual style.
+        * rendering/MarkerSubrange.h:
+
 2018-01-24  Youenn Fablet  <youenn@apple.com>
 
         Fetch response should copy its url from the request if null
index c490032..f447463 100644 (file)
@@ -393,13 +393,20 @@ bool InlineTextBox::emphasisMarkExistsAndIsAbove(const RenderStyle& style, bool&
 }
 
 struct InlineTextBox::MarkerSubrangeStyle {
-    bool operator==(const MarkerSubrangeStyle& other) const
+    bool operator==(const MarkerSubrangeStyle& other) const = delete;
+    bool operator!=(const MarkerSubrangeStyle& other) const = delete;
+    static bool areBackgroundMarkerSubrangeStylesEqual(const MarkerSubrangeStyle& a, const MarkerSubrangeStyle& b)
     {
-        return backgroundColor == other.backgroundColor && textStyles == other.textStyles
-            && textDecorationStyles == other.textDecorationStyles && textShadow == other.textShadow
-            && alpha == other.alpha;
+        return a.backgroundColor == b.backgroundColor;
+    }
+    static bool areForegroundMarkerSubrangeStylesEqual(const MarkerSubrangeStyle& a, const MarkerSubrangeStyle& b)
+    {
+        return a.textStyles == b.textStyles && a.textShadow == b.textShadow && a.alpha == b.alpha;
+    }
+    static bool areDecorationMarkerSubrangeStylesEqual(const MarkerSubrangeStyle& a, const MarkerSubrangeStyle& b)
+    {
+        return a.textDecorationStyles == b.textDecorationStyles && a.textShadow == b.textShadow;
     }
-    bool operator!=(const MarkerSubrangeStyle& other) const { return !(*this == other); }
 
     Color backgroundColor;
     TextPaintStyle textStyles;
@@ -510,7 +517,11 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
         }
 #endif
         auto styledSubranges = subdivideAndResolveStyle(subranges, unmarkedStyle, paintInfo);
-        paintMarkerSubranges(context, TextPaintPhase::Background, boxRect, styledSubranges);
+
+        // Coalesce styles of adjacent subranges to minimize the number of drawing commands.
+        auto coalescedStyledSubranges = coalesceAdjacentSubranges(styledSubranges, &MarkerSubrangeStyle::areBackgroundMarkerSubrangeStylesEqual);
+
+        paintMarkerSubranges(context, TextPaintPhase::Background, boxRect, coalescedStyledSubranges);
     }
 
     // FIXME: Right now, InlineTextBoxes never call addRelevantUnpaintedObject() even though they might
@@ -553,7 +564,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
     if (!isPrinting && paintInfo.paintBehavior & PaintBehaviorExcludeSelection)
         styledSubranges.removeAllMatching([] (const StyledMarkerSubrange& subrange) { return subrange.type == MarkerSubrange::Selection; });
 
-    paintMarkerSubranges(context, TextPaintPhase::Foreground, boxRect, styledSubranges);
+    // Coalesce styles of adjacent subranges to minimize the number of drawing commands.
+    auto coalescedStyledSubranges = coalesceAdjacentSubranges(styledSubranges, &MarkerSubrangeStyle::areForegroundMarkerSubrangeStylesEqual);
+
+    paintMarkerSubranges(context, TextPaintPhase::Foreground, boxRect, coalescedStyledSubranges);
 
     // Paint decorations
     TextDecoration textDecorations = lineStyle.textDecorationsInEffect();
@@ -587,7 +601,11 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
                 textDecorationSelectionClipOutRect.setWidth(logicalSelectionWidth);
             }
         }
-        paintMarkerSubranges(context, TextPaintPhase::Decoration, boxRect, styledSubranges, textDecorationSelectionClipOutRect);
+
+        // Coalesce styles of adjacent subranges to minimize the number of drawing commands.
+        auto coalescedStyledSubranges = coalesceAdjacentSubranges(styledSubranges, &MarkerSubrangeStyle::areDecorationMarkerSubrangeStylesEqual);
+
+        paintMarkerSubranges(context, TextPaintPhase::Decoration, boxRect, coalescedStyledSubranges, textDecorationSelectionClipOutRect);
     }
 
     // 3. Paint fancy decorations, including composition underlines and platform-specific underlines for spelling errors, grammar errors, et cetera.
@@ -765,25 +783,46 @@ auto InlineTextBox::subdivideAndResolveStyle(const Vector<MarkerSubrange>& subra
     if (subrangesToSubdivide.isEmpty())
         return { };
 
-    auto areAdjacentSubrangesWithSameStyle = [] (const StyledMarkerSubrange& a, const StyledMarkerSubrange& b) {
-        return a.endOffset == b.startOffset && a.style == b.style;
-    };
+    auto subranges = subdivide(subrangesToSubdivide);
 
-    auto subranges = subdivide(subrangesToSubdivide, OverlapStrategy::FrontmostWithLongestEffectiveRange);
+    // Compute frontmost overlapping styled subranges.
+    Vector<StyledMarkerSubrange> frontmostSubranges;
+    frontmostSubranges.reserveInitialCapacity(subranges.size());
+    frontmostSubranges.uncheckedAppend(resolveStyleForSubrange(subranges[0], baseStyle, paintInfo));
+    for (auto it = subranges.begin() + 1, end = subranges.end(); it != end; ++it) {
+        StyledMarkerSubrange& previousStyledSubrange = frontmostSubranges.last();
+        if (previousStyledSubrange.startOffset == it->startOffset && previousStyledSubrange.endOffset == it->endOffset) {
+            // Subranges completely cover each other.
+            previousStyledSubrange = resolveStyleForSubrange(*it, previousStyledSubrange.style, paintInfo);
+            continue;
+        }
+        frontmostSubranges.uncheckedAppend(resolveStyleForSubrange(*it, baseStyle, paintInfo));
+    }
+
+    return frontmostSubranges;
+}
+
+auto InlineTextBox::coalesceAdjacentSubranges(const Vector<StyledMarkerSubrange>& subrangesToCoalesce, MarkerSubrangeStylesEqualityFunction areMarkerSubrangeStylesEqual) -> Vector<StyledMarkerSubrange>
+{
+    if (subrangesToCoalesce.isEmpty())
+        return { };
+
+    auto areAdjacentSubrangesWithSameStyle = [&] (const StyledMarkerSubrange& a, const StyledMarkerSubrange& b) {
+        return a.endOffset == b.startOffset && areMarkerSubrangeStylesEqual(a.style, b.style);
+    };
 
-    // Coallesce styles of adjacent subranges to minimize the number of drawing commands.
     Vector<StyledMarkerSubrange> styledSubranges;
-    styledSubranges.reserveInitialCapacity(subranges.size());
-    styledSubranges.uncheckedAppend(resolveStyleForSubrange(subranges[0], baseStyle, paintInfo));
-    for (auto it = subranges.begin() + 1, end = subranges.end(); it != end; ++it) {
+    styledSubranges.reserveInitialCapacity(subrangesToCoalesce.size());
+    styledSubranges.uncheckedAppend(subrangesToCoalesce[0]);
+    for (auto it = subrangesToCoalesce.begin() + 1, end = subrangesToCoalesce.end(); it != end; ++it) {
         StyledMarkerSubrange& previousStyledSubrange = styledSubranges.last();
-        auto currentStyledSubrange = resolveStyleForSubrange(*it, baseStyle, paintInfo);
-        if (areAdjacentSubrangesWithSameStyle(previousStyledSubrange, currentStyledSubrange)) {
-            previousStyledSubrange.endOffset = currentStyledSubrange.endOffset;
+        if (areAdjacentSubrangesWithSameStyle(previousStyledSubrange, *it)) {
+            previousStyledSubrange.endOffset = it->endOffset;
             continue;
         }
-        styledSubranges.uncheckedAppend(currentStyledSubrange);
+        styledSubranges.uncheckedAppend(*it);
     }
+
     return styledSubranges;
 }
 
index 79b1078..ca7741e 100644 (file)
@@ -163,6 +163,9 @@ private:
     StyledMarkerSubrange resolveStyleForSubrange(const MarkerSubrange&, const MarkerSubrangeStyle& baseStyle, const PaintInfo&);
     Vector<StyledMarkerSubrange> subdivideAndResolveStyle(const Vector<MarkerSubrange>&, const MarkerSubrangeStyle& baseStyle, const PaintInfo&);
 
+    using MarkerSubrangeStylesEqualityFunction = bool (*)(const MarkerSubrangeStyle&, const MarkerSubrangeStyle&);
+    Vector<StyledMarkerSubrange> coalesceAdjacentSubranges(const Vector<StyledMarkerSubrange>&, MarkerSubrangeStylesEqualityFunction);
+
     FloatPoint textOriginFromBoxRect(const FloatRect&) const;
 
     void paintMarkerSubranges(GraphicsContext&, TextPaintPhase, const FloatRect& boxRect, const Vector<StyledMarkerSubrange>&, const FloatRect& decorationClipOutRect = { });
index 5b48073..4dee4fd 100644 (file)
@@ -67,22 +67,14 @@ Vector<MarkerSubrange> subdivide(const Vector<MarkerSubrange>& subranges, Overla
     unsigned offsetSoFar = offsets[0].value;
     for (unsigned i = 1; i < numberOfOffsets; ++i) {
         if (offsets[i].value > offsets[i - 1].value) {
-            if (overlapStrategy == OverlapStrategy::Frontmost || overlapStrategy == OverlapStrategy::FrontmostWithLongestEffectiveRange) {
+            if (overlapStrategy == OverlapStrategy::Frontmost) {
                 std::optional<unsigned> frontmost;
                 for (unsigned j = 0; j < i; ++j) {
                     if (!processedSubranges.contains(offsets[j].subrange) && (!frontmost || offsets[j].subrange->type > offsets[*frontmost].subrange->type))
                         frontmost = j;
                 }
-                if (frontmost) {
-                    if (overlapStrategy == OverlapStrategy::FrontmostWithLongestEffectiveRange && !result.isEmpty()) {
-                        auto& previous = result.last();
-                        if (previous.endOffset == offsetSoFar && previous.type == offsets[*frontmost].subrange->type && previous.marker == offsets[*frontmost].subrange->marker)
-                            previous.endOffset = offsets[i].value;
-                        else
-                            result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].subrange->type, offsets[*frontmost].subrange->marker });
-                    } else
-                        result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].subrange->type, offsets[*frontmost].subrange->marker });
-                }
+                if (frontmost)
+                    result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].subrange->type, offsets[*frontmost].subrange->marker });
             } else {
                 // The appended subranges may not be in paint order. We will fix this up at the end of this function.
                 for (unsigned j = 0; j < i; ++j) {
index cb4796d..384615f 100644 (file)
@@ -70,7 +70,7 @@ struct MarkerSubrange {
     }
 };
 
-enum class OverlapStrategy { None, Frontmost, FrontmostWithLongestEffectiveRange };
+enum class OverlapStrategy { None, Frontmost };
 WEBCORE_EXPORT Vector<MarkerSubrange> subdivide(const Vector<MarkerSubrange>&, OverlapStrategy = OverlapStrategy::None);
 
 }
index ea88e99..2a60582 100644 (file)
@@ -1,3 +1,16 @@
+2018-01-24  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r226138): Selecting a line that ends with zero-width joiner (ZWJ) may cause text transformation
+        https://bugs.webkit.org/show_bug.cgi?id=181993
+        <rdar://problem/36421080>
+
+        Reviewed by David Hyatt.
+
+        Remove unit test for overlap strategy FrontmostWithLongestEffectiveRange
+        as we no longer support this strategy.
+
+        * TestWebKitAPI/Tests/WebCore/MarkerSubrange.cpp:
+
 2018-01-24  David Kilzer  <ddkilzer@apple.com>
 
         check-webkit-style reports false-positive whitespace/braces warning about blocks with return types as arguments in Objective-C
index 295f437..08d7259 100644 (file)
@@ -214,21 +214,4 @@ TEST(MarkerSubrange, SubdivideGrammarAndSelectionOverlapFrontmost)
         EXPECT_EQ(expectedSubranges[i], results[i]);
 }
 
-TEST(MarkerSubrange, SubdivideGrammarAndSelectionOverlapFrontmostWithLongestEffectiveRange)
-{
-    Vector<MarkerSubrange> subranges {
-        MarkerSubrange { 0, 40, MarkerSubrange::GrammarError },
-        MarkerSubrange { 2, 60, MarkerSubrange::Selection },
-        MarkerSubrange { 50, 60, MarkerSubrange::GrammarError },
-    };
-    Vector<MarkerSubrange> expectedSubranges {
-        MarkerSubrange { 0, 2, MarkerSubrange::GrammarError },
-        MarkerSubrange { 2, 60, MarkerSubrange::Selection },
-    };
-    auto results = subdivide(subranges, OverlapStrategy::FrontmostWithLongestEffectiveRange);
-    ASSERT_EQ(expectedSubranges.size(), results.size());
-    for (size_t i = 0; i < expectedSubranges.size(); ++i)
-        EXPECT_EQ(expectedSubranges[i], results[i]);
-}
-
 }