⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 278621 in webkit


Ignore:
Timestamp:
Jun 8, 2021, 11:02:20 AM (5 years ago)
Author:
Antti Koivisto
Message:

Factor MarkedText collection out of LegacyInlineTextBox
https://bugs.webkit.org/show_bug.cgi?id=226731

Reviewed by Sam Weinig.

Source/WebCore:

Move more code out from the legacy inline classes.

  • rendering/LegacyInlineTextBox.cpp:

(WebCore::LegacyInlineTextBox::paint):
(WebCore::LegacyInlineTextBox::hasMarkers const):
(WebCore::LegacyInlineTextBox::paintPlatformDocumentMarkers):
(WebCore::LegacyInlineTextBox::calculateUnionOfAllDocumentMarkerBounds const):
(WebCore::LegacyInlineTextBox::paintMarkedTexts):
(WebCore::LegacyInlineTextBox::highlightStartEnd const): Deleted.
(WebCore::LegacyInlineTextBox::collectMarkedTextsForDraggedContent): Deleted.
(WebCore::LegacyInlineTextBox::collectMarkedTextsForDocumentMarkers const): Deleted.
(WebCore::LegacyInlineTextBox::collectMarkedTextsForHighlights const): Deleted.

  • rendering/LegacyInlineTextBox.h:

(WebCore::LegacyInlineTextBox::paintMarkedTexts):

  • rendering/MarkedText.cpp:

(WebCore::MarkedText::subdivide):
(WebCore::MarkedText::collectForHighlights):
(WebCore::MarkedText::collectForDocumentMarkers):
(WebCore::MarkedText::collectForDraggedContent):
(WebCore::subdivide): Deleted.

  • rendering/MarkedText.h:

(WebCore::MarkedText::operator== const):

  • rendering/MarkedTextStyle.cpp:

(WebCore::subdivideAndResolveStyle):

Tools:

  • TestWebKitAPI/Tests/WebCore/MarkedText.cpp:

(TestWebKitAPI::TEST):

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r278620 r278621  
     12021-06-08  Antti Koivisto  <antti@apple.com>
     2
     3        Factor MarkedText collection out of LegacyInlineTextBox
     4        https://bugs.webkit.org/show_bug.cgi?id=226731
     5
     6        Reviewed by Sam Weinig.
     7
     8        Move more code out from the legacy inline classes.
     9
     10        * rendering/LegacyInlineTextBox.cpp:
     11        (WebCore::LegacyInlineTextBox::paint):
     12        (WebCore::LegacyInlineTextBox::hasMarkers const):
     13        (WebCore::LegacyInlineTextBox::paintPlatformDocumentMarkers):
     14        (WebCore::LegacyInlineTextBox::calculateUnionOfAllDocumentMarkerBounds const):
     15        (WebCore::LegacyInlineTextBox::paintMarkedTexts):
     16        (WebCore::LegacyInlineTextBox::highlightStartEnd const): Deleted.
     17        (WebCore::LegacyInlineTextBox::collectMarkedTextsForDraggedContent): Deleted.
     18        (WebCore::LegacyInlineTextBox::collectMarkedTextsForDocumentMarkers const): Deleted.
     19        (WebCore::LegacyInlineTextBox::collectMarkedTextsForHighlights const): Deleted.
     20        * rendering/LegacyInlineTextBox.h:
     21        (WebCore::LegacyInlineTextBox::paintMarkedTexts):
     22        * rendering/MarkedText.cpp:
     23        (WebCore::MarkedText::subdivide):
     24        (WebCore::MarkedText::collectForHighlights):
     25        (WebCore::MarkedText::collectForDocumentMarkers):
     26        (WebCore::MarkedText::collectForDraggedContent):
     27        (WebCore::subdivide): Deleted.
     28        * rendering/MarkedText.h:
     29        (WebCore::MarkedText::operator== const):
     30        * rendering/MarkedTextStyle.cpp:
     31        (WebCore::subdivideAndResolveStyle):
     32
    1332021-06-08  Truitt Savell  <tsavell@apple.com>
    234
  • trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp

    r278561 r278621  
    3737
    3838#include "HighlightData.h"
    39 #include "HighlightRegister.h"
    4039#include "HitTestResult.h"
    4140#include "ImageBuffer.h"
     
    493492            paintCompositionBackground(paintInfo, boxOrigin);
    494493
    495         Vector<MarkedText> markedTexts = collectMarkedTextsForDocumentMarkers(TextPaintPhase::Background);
    496         auto highlightMarkedTexts = collectMarkedTextsForHighlights(TextPaintPhase::Background);
    497         if (!highlightMarkedTexts.isEmpty())
    498             markedTexts.appendVector(WTFMove(highlightMarkedTexts));
     494        auto selectableRange = this->selectableRange();
     495
     496        Vector<MarkedText> markedTexts;
     497        markedTexts.appendVector(MarkedText::collectForDocumentMarkers(renderer(), selectableRange, MarkedText::PaintPhase::Background));
     498        markedTexts.appendVector(MarkedText::collectForHighlights(renderer(), parent()->renderer(), selectableRange, MarkedText::PaintPhase::Background));
     499
    499500#if ENABLE(TEXT_SELECTION)
    500501        if (haveSelection && !useCustomUnderlines && !context.paintingDisabled()) {
     
    509510        auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areBackgroundMarkedTextStylesEqual);
    510511
    511         paintMarkedTexts(paintInfo, TextPaintPhase::Background, boxRect, coalescedStyledMarkedTexts);
     512        paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Background, boxRect, coalescedStyledMarkedTexts);
    512513    }
    513514
     
    526527    Vector<MarkedText> markedTexts;
    527528    if (paintInfo.phase != PaintPhase::Selection) {
     529        auto selectableRange = this->selectableRange();
     530
    528531        // The marked texts for the gaps between document markers and selection are implicitly created by subdividing the entire line.
    529         auto selectableRange = this->selectableRange();
    530532        markedTexts.append({ selectableRange.clamp(m_start), selectableRange.clamp(end()), MarkedText::Unmarked });
     533       
    531534        if (!isPrinting) {
    532             markedTexts.appendVector(collectMarkedTextsForDocumentMarkers(TextPaintPhase::Foreground));
    533             auto highlightMarkedTexts = collectMarkedTextsForHighlights(TextPaintPhase::Foreground);
    534             if (!highlightMarkedTexts.isEmpty())
    535                 markedTexts.appendVector(WTFMove(highlightMarkedTexts));
     535            markedTexts.appendVector(MarkedText::collectForDocumentMarkers(renderer(), selectableRange, MarkedText::PaintPhase::Foreground));
     536            markedTexts.appendVector(MarkedText::collectForHighlights(renderer(), parent()->renderer(), selectableRange, MarkedText::PaintPhase::Foreground));
    536537
    537538            bool shouldPaintDraggedContent = !(paintInfo.paintBehavior.contains(PaintBehavior::ExcludeSelection));
    538539            if (shouldPaintDraggedContent) {
    539                 auto markedTextsForDraggedContent = collectMarkedTextsForDraggedContent();
     540                auto markedTextsForDraggedContent = MarkedText::collectForDraggedContent(renderer(), selectableRange);
    540541                if (!markedTextsForDraggedContent.isEmpty()) {
    541542                    shouldPaintSelectionForeground = false;
     
    565566    auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areForegroundMarkedTextStylesEqual);
    566567
    567     paintMarkedTexts(paintInfo, TextPaintPhase::Foreground, boxRect, coalescedStyledMarkedTexts);
     568    paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Foreground, boxRect, coalescedStyledMarkedTexts);
    568569
    569570    // Paint decorations
    570571    auto textDecorations = lineStyle.textDecorationsInEffect();
    571     bool highlightDecorations = !collectMarkedTextsForHighlights(TextPaintPhase::Decoration).isEmpty();
     572    bool highlightDecorations = !MarkedText::collectForHighlights(renderer(), parent()->renderer(), selectableRange(), MarkedText::PaintPhase::Decoration).isEmpty();
    572573    bool lineDecorations = !textDecorations.isEmpty();
    573574    if ((lineDecorations || highlightDecorations) && paintInfo.phase != PaintPhase::Selection) {
     
    604605        auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areDecorationMarkedTextStylesEqual);
    605606
    606         paintMarkedTexts(paintInfo, TextPaintPhase::Decoration, boxRect, coalescedStyledMarkedTexts, textDecorationSelectionClipOutRect);
     607        paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Decoration, boxRect, coalescedStyledMarkedTexts, textDecorationSelectionClipOutRect);
    607608    }
    608609
     
    650651}
    651652
    652 std::pair<unsigned, unsigned> LegacyInlineTextBox::highlightStartEnd(HighlightData& rangeData) const
    653 {
    654     return rangeData.rangeForTextBox(renderer(), selectableRange());
    655 }
    656 
    657653bool LegacyInlineTextBox::hasMarkers() const
    658654{
    659     return collectMarkedTextsForDocumentMarkers(TextPaintPhase::Decoration).size();
     655    return MarkedText::collectForDocumentMarkers(renderer(), selectableRange(), MarkedText::PaintPhase::Decoration).size();
    660656}
    661657
     
    663659{
    664660    // This must match calculateUnionOfAllDocumentMarkerBounds().
    665     for (auto& markedText : subdivide(collectMarkedTextsForDocumentMarkers(TextPaintPhase::Decoration), OverlapStrategy::Frontmost))
     661    auto markedTexts = MarkedText::collectForDocumentMarkers(renderer(), selectableRange(), MarkedText::PaintPhase::Decoration);
     662    for (auto& markedText : MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost))
    666663        paintPlatformDocumentMarker(context, boxOrigin, markedText);
    667664}
     
    671668    // This must match paintPlatformDocumentMarkers().
    672669    FloatRect result;
    673     for (auto& markedText : subdivide(collectMarkedTextsForDocumentMarkers(TextPaintPhase::Decoration), OverlapStrategy::Frontmost))
     670    auto markedTexts = MarkedText::collectForDocumentMarkers(renderer(), selectableRange(), MarkedText::PaintPhase::Decoration);
     671    for (auto& markedText : MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost))
    674672        result = unionRect(result, calculateDocumentMarkerBounds(markedText));
    675673    return result;
     
    732730}
    733731
    734 Vector<MarkedText> LegacyInlineTextBox::collectMarkedTextsForDraggedContent()
    735 {
    736     using DraggendContentRange = std::pair<unsigned, unsigned>;
    737     auto draggedContentRanges = renderer().draggedContentRangesBetweenOffsets(m_start, m_start + m_len);
    738 
    739     Vector<MarkedText> result = draggedContentRanges.map([this] (const DraggendContentRange& range) -> MarkedText {
    740         auto [clampedStart, clampedEnd] = selectableRange().clamp(range.first, range.second);
    741         return { clampedStart, clampedEnd, MarkedText::DraggedContent };
    742     });
    743     return result;
    744 }
    745 
    746 Vector<MarkedText> LegacyInlineTextBox::collectMarkedTextsForDocumentMarkers(TextPaintPhase phase) const
    747 {
    748     ASSERT_ARG(phase, phase == TextPaintPhase::Background || phase == TextPaintPhase::Foreground || phase == TextPaintPhase::Decoration);
    749 
    750     if (!renderer().textNode())
    751         return { };
    752 
    753     Vector<RenderedDocumentMarker*> markers = renderer().document().markers().markersFor(*renderer().textNode());
    754 
    755     auto markedTextTypeForMarkerType = [] (DocumentMarker::MarkerType type) {
    756         switch (type) {
    757         case DocumentMarker::Spelling:
    758             return MarkedText::SpellingError;
    759         case DocumentMarker::Grammar:
    760             return MarkedText::GrammarError;
    761         case DocumentMarker::CorrectionIndicator:
    762             return MarkedText::Correction;
    763         case DocumentMarker::TextMatch:
    764             return MarkedText::TextMatch;
    765         case DocumentMarker::DictationAlternatives:
    766             return MarkedText::DictationAlternatives;
    767 #if PLATFORM(IOS_FAMILY)
    768         case DocumentMarker::DictationPhraseWithAlternatives:
    769             return MarkedText::DictationPhraseWithAlternatives;
    770 #endif
    771         default:
    772             return MarkedText::Unmarked;
    773         }
    774     };
    775 
    776     Vector<MarkedText> markedTexts;
    777     markedTexts.reserveInitialCapacity(markers.size());
    778 
    779     // Give any document markers that touch this run a chance to draw before the text has been drawn.
    780     // Note end() points at the last char, not one past it like endOffset and ranges do.
    781     for (auto* marker : markers) {
    782         // Collect either the background markers or the foreground markers, but not both
    783         switch (marker->type()) {
    784         case DocumentMarker::Grammar:
    785         case DocumentMarker::Spelling:
    786         case DocumentMarker::CorrectionIndicator:
    787         case DocumentMarker::Replacement:
    788         case DocumentMarker::DictationAlternatives:
    789 #if PLATFORM(IOS_FAMILY)
    790         // FIXME: Remove the PLATFORM(IOS_FAMILY)-guard.
    791         case DocumentMarker::DictationPhraseWithAlternatives:
    792 #endif
    793             if (phase != TextPaintPhase::Decoration)
    794                 continue;
    795             break;
    796         case DocumentMarker::TextMatch:
    797             if (!renderer().frame().editor().markedTextMatchesAreHighlighted())
    798                 continue;
    799             if (phase == TextPaintPhase::Decoration)
    800                 continue;
    801             break;
    802 #if ENABLE(TELEPHONE_NUMBER_DETECTION)
    803         case DocumentMarker::TelephoneNumber:
    804             if (!renderer().frame().editor().markedTextMatchesAreHighlighted())
    805                 continue;
    806             if (phase != TextPaintPhase::Background)
    807                 continue;
    808             break;
    809 #endif
    810         default:
    811             continue;
    812         }
    813 
    814         if (marker->endOffset() <= start()) {
    815             // Marker is completely before this run. This might be a marker that sits before the
    816             // first run we draw, or markers that were within runs we skipped due to truncation.
    817             continue;
    818         }
    819 
    820         if (marker->startOffset() >= end()) {
    821             // Marker is completely after this run, bail. A later run will paint it.
    822             break;
    823         }
    824 
    825         // Marker intersects this run. Collect it.
    826         switch (marker->type()) {
    827         case DocumentMarker::Spelling:
    828         case DocumentMarker::CorrectionIndicator:
    829         case DocumentMarker::DictationAlternatives:
    830         case DocumentMarker::Grammar:
    831 #if PLATFORM(IOS_FAMILY)
    832         // FIXME: See <rdar://problem/8933352>. Also, remove the PLATFORM(IOS_FAMILY)-guard.
    833         case DocumentMarker::DictationPhraseWithAlternatives:
    834 #endif
    835         case DocumentMarker::TextMatch: {
    836             auto [clampedStart, clampedEnd] = selectableRange().clamp(marker->startOffset(), marker->endOffset());
    837             markedTexts.uncheckedAppend({ clampedStart, clampedEnd, markedTextTypeForMarkerType(marker->type()), marker });
    838             break;
    839         }
    840         case DocumentMarker::Replacement:
    841             break;
    842 #if ENABLE(TELEPHONE_NUMBER_DETECTION)
    843         case DocumentMarker::TelephoneNumber:
    844             break;
    845 #endif
    846         default:
    847             ASSERT_NOT_REACHED();
    848         }
    849     }
    850     return markedTexts;
    851 }
    852 
    853 Vector<MarkedText> LegacyInlineTextBox::collectMarkedTextsForHighlights(TextPaintPhase phase) const
    854 {
    855     ASSERT_ARG(phase, phase == TextPaintPhase::Background || phase == TextPaintPhase::Foreground || phase == TextPaintPhase::Decoration);
    856     UNUSED_PARAM(phase);
    857     if (!renderer().textNode())
    858         return { };
    859 
    860     Vector<MarkedText> markedTexts;
    861     HighlightData highlightData;
    862     if (RuntimeEnabledFeatures::sharedFeatures().highlightAPIEnabled()) {
    863         auto& parentRenderer = parent()->renderer();
    864         auto& parentStyle = parentRenderer.style();
    865         if (auto highlightRegister = renderer().document().highlightRegisterIfExists()) {
    866             for (auto& highlight : highlightRegister->map()) {
    867                 auto renderStyle = parentRenderer.getUncachedPseudoStyle({ PseudoId::Highlight, highlight.key }, &parentStyle);
    868                 if (!renderStyle)
    869                     continue;
    870                 if (renderStyle->textDecorationsInEffect().isEmpty() && phase == TextPaintPhase::Decoration)
    871                     continue;
    872                 for (auto& rangeData : highlight.value->rangesData()) {
    873                     if (!highlightData.setRenderRange(rangeData))
    874                         continue;
    875 
    876                     auto [highlightStart, highlightEnd] = highlightStartEnd(highlightData);
    877                     if (highlightStart < highlightEnd)
    878                         markedTexts.append({ highlightStart, highlightEnd, MarkedText::Highlight, nullptr, highlight.key });
    879                 }
    880             }
    881         }
    882     }
    883 #if ENABLE(APP_HIGHLIGHTS)
    884     if (auto appHighlightRegister = renderer().document().appHighlightRegisterIfExists()) {
    885         if (appHighlightRegister->highlightsVisibility() == HighlightVisibility::Visible) {
    886             for (auto& highlight : appHighlightRegister->map()) {
    887                 for (auto& rangeData : highlight.value->rangesData()) {
    888                     if (!highlightData.setRenderRange(rangeData))
    889                         continue;
    890 
    891                     auto [highlightStart, highlightEnd] = highlightStartEnd(highlightData);
    892                     if (highlightStart < highlightEnd)
    893                         markedTexts.append({ highlightStart, highlightEnd, MarkedText::AppHighlight });
    894                 }
    895             }
    896         }
    897     }
    898 #endif
    899     return markedTexts;
    900 }
    901 
    902732FloatPoint LegacyInlineTextBox::textOriginFromBoxRect(const FloatRect& boxRect) const
    903733{
     
    914744}
    915745
    916 void LegacyInlineTextBox::paintMarkedTexts(PaintInfo& paintInfo, TextPaintPhase phase, const FloatRect& boxRect, const Vector<StyledMarkedText>& markedTexts, const FloatRect& decorationClipOutRect)
     746void LegacyInlineTextBox::paintMarkedTexts(PaintInfo& paintInfo, MarkedText::PaintPhase phase, const FloatRect& boxRect, const Vector<StyledMarkedText>& markedTexts, const FloatRect& decorationClipOutRect)
    917747{
    918748    switch (phase) {
    919     case TextPaintPhase::Background:
     749    case MarkedText::PaintPhase::Background:
    920750        for (auto& markedText : markedTexts)
    921751            paintMarkedTextBackground(paintInfo, boxRect.location(), markedText.style.backgroundColor, markedText.startOffset, markedText.endOffset);
    922752        return;
    923     case TextPaintPhase::Foreground:
     753    case MarkedText::PaintPhase::Foreground:
    924754        for (auto& markedText : markedTexts)
    925755            paintMarkedTextForeground(paintInfo, boxRect, markedText);
    926756        return;
    927     case TextPaintPhase::Decoration:
     757    case MarkedText::PaintPhase::Decoration:
    928758        for (auto& markedText : markedTexts)
    929759            paintMarkedTextDecoration(paintInfo, boxRect, decorationClipOutRect, markedText);
  • trunk/Source/WebCore/rendering/LegacyInlineTextBox.h

    r278561 r278621  
    2424
    2525#include "LegacyInlineBox.h"
     26#include "MarkedText.h"
    2627#include "RenderText.h"
    2728#include "TextRun.h"
     
    124125    bool isSelectable(unsigned startPosition, unsigned endPosition) const;
    125126    std::pair<unsigned, unsigned> selectionStartEnd() const;
    126     std::pair<unsigned, unsigned> highlightStartEnd(HighlightData&) const;
    127127
    128128protected:
     
    164164
    165165private:
    166     enum class TextPaintPhase { Background, Foreground, Decoration };
    167 
    168     Vector<MarkedText> collectMarkedTextsForDraggedContent();
    169     Vector<MarkedText> collectMarkedTextsForDocumentMarkers(TextPaintPhase) const;
    170     Vector<MarkedText> collectMarkedTextsForHighlights(TextPaintPhase) const;
    171 
    172166    FloatPoint textOriginFromBoxRect(const FloatRect&) const;
    173167
    174     void paintMarkedTexts(PaintInfo&, TextPaintPhase, const FloatRect& boxRect, const Vector<StyledMarkedText>&, const FloatRect& decorationClipOutRect = { });
     168    void paintMarkedTexts(PaintInfo&, MarkedText::PaintPhase, const FloatRect& boxRect, const Vector<StyledMarkedText>&, const FloatRect& decorationClipOutRect = { });
    175169
    176170    void paintPlatformDocumentMarker(GraphicsContext&, const FloatPoint& boxOrigin, const MarkedText&);
  • trunk/Source/WebCore/rendering/MarkedText.cpp

    r278253 r278621  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2727#include "MarkedText.h"
    2828
     29#include "Document.h"
     30#include "DocumentMarkerController.h"
     31#include "Editor.h"
     32#include "ElementRuleCollector.h"
     33#include "HighlightRegister.h"
     34#include "RenderBoxModelObject.h"
     35#include "RenderText.h"
     36#include "RenderedDocumentMarker.h"
     37#include "RuntimeEnabledFeatures.h"
    2938#include <algorithm>
    3039#include <wtf/HashSet.h>
     
    3241namespace WebCore {
    3342
    34 Vector<MarkedText> subdivide(const Vector<MarkedText>& markedTexts, OverlapStrategy overlapStrategy)
     43Vector<MarkedText> MarkedText::subdivide(const Vector<MarkedText>& markedTexts, OverlapStrategy overlapStrategy)
    3544{
    3645    if (markedTexts.isEmpty())
     
    94103}
    95104
    96 }
    97 
    98 
     105Vector<MarkedText> MarkedText::collectForHighlights(RenderText& renderer, RenderBoxModelObject& parentRenderer, const TextBoxSelectableRange& selectableRange, PaintPhase phase)
     106{
     107    Vector<MarkedText> markedTexts;
     108    HighlightData highlightData;
     109    if (RuntimeEnabledFeatures::sharedFeatures().highlightAPIEnabled()) {
     110        auto& parentStyle = parentRenderer.style();
     111        if (auto highlightRegister = renderer.document().highlightRegisterIfExists()) {
     112            for (auto& highlight : highlightRegister->map()) {
     113                auto renderStyle = parentRenderer.getUncachedPseudoStyle({ PseudoId::Highlight, highlight.key }, &parentStyle);
     114                if (!renderStyle)
     115                    continue;
     116                if (renderStyle->textDecorationsInEffect().isEmpty() && phase == PaintPhase::Decoration)
     117                    continue;
     118                for (auto& rangeData : highlight.value->rangesData()) {
     119                    if (!highlightData.setRenderRange(rangeData))
     120                        continue;
     121
     122                    auto [highlightStart, highlightEnd] = highlightData.rangeForTextBox(renderer, selectableRange);
     123                    if (highlightStart < highlightEnd)
     124                        markedTexts.append({ highlightStart, highlightEnd, MarkedText::Highlight, nullptr, highlight.key });
     125                }
     126            }
     127        }
     128    }
     129#if ENABLE(APP_HIGHLIGHTS)
     130    if (auto appHighlightRegister = renderer.document().appHighlightRegisterIfExists()) {
     131        if (appHighlightRegister->highlightsVisibility() == HighlightVisibility::Visible) {
     132            for (auto& highlight : appHighlightRegister->map()) {
     133                for (auto& rangeData : highlight.value->rangesData()) {
     134                    if (!highlightData.setRenderRange(rangeData))
     135                        continue;
     136
     137                    auto [highlightStart, highlightEnd] = highlightData.rangeForTextBox(renderer, selectableRange);
     138                    if (highlightStart < highlightEnd)
     139                        markedTexts.append({ highlightStart, highlightEnd, MarkedText::AppHighlight });
     140                }
     141            }
     142        }
     143    }
     144#endif
     145    return markedTexts;
     146}
     147
     148Vector<MarkedText> MarkedText::collectForDocumentMarkers(RenderText& renderer, const TextBoxSelectableRange& selectableRange, PaintPhase phase)
     149{
     150    if (!renderer.textNode())
     151        return { };
     152
     153    Vector<RenderedDocumentMarker*> markers = renderer.document().markers().markersFor(*renderer.textNode());
     154
     155    auto markedTextTypeForMarkerType = [] (DocumentMarker::MarkerType type) {
     156        switch (type) {
     157        case DocumentMarker::Spelling:
     158            return MarkedText::SpellingError;
     159        case DocumentMarker::Grammar:
     160            return MarkedText::GrammarError;
     161        case DocumentMarker::CorrectionIndicator:
     162            return MarkedText::Correction;
     163        case DocumentMarker::TextMatch:
     164            return MarkedText::TextMatch;
     165        case DocumentMarker::DictationAlternatives:
     166            return MarkedText::DictationAlternatives;
     167#if PLATFORM(IOS_FAMILY)
     168        case DocumentMarker::DictationPhraseWithAlternatives:
     169            return MarkedText::DictationPhraseWithAlternatives;
     170#endif
     171        default:
     172            return MarkedText::Unmarked;
     173        }
     174    };
     175
     176    Vector<MarkedText> markedTexts;
     177    markedTexts.reserveInitialCapacity(markers.size());
     178
     179    // Give any document markers that touch this run a chance to draw before the text has been drawn.
     180    // Note end() points at the last char, not one past it like endOffset and ranges do.
     181    for (auto* marker : markers) {
     182        // Collect either the background markers or the foreground markers, but not both
     183        switch (marker->type()) {
     184        case DocumentMarker::Grammar:
     185        case DocumentMarker::Spelling:
     186        case DocumentMarker::CorrectionIndicator:
     187        case DocumentMarker::Replacement:
     188        case DocumentMarker::DictationAlternatives:
     189#if PLATFORM(IOS_FAMILY)
     190        // FIXME: Remove the PLATFORM(IOS_FAMILY)-guard.
     191        case DocumentMarker::DictationPhraseWithAlternatives:
     192#endif
     193            if (phase != MarkedText::PaintPhase::Decoration)
     194                continue;
     195            break;
     196        case DocumentMarker::TextMatch:
     197            if (!renderer.frame().editor().markedTextMatchesAreHighlighted())
     198                continue;
     199            if (phase == MarkedText::PaintPhase::Decoration)
     200                continue;
     201            break;
     202#if ENABLE(TELEPHONE_NUMBER_DETECTION)
     203        case DocumentMarker::TelephoneNumber:
     204            if (!renderer.frame().editor().markedTextMatchesAreHighlighted())
     205                continue;
     206            if (phase != MarkedText::PaintPhase::Background)
     207                continue;
     208            break;
     209#endif
     210        default:
     211            continue;
     212        }
     213
     214        if (marker->endOffset() <= selectableRange.start) {
     215            // Marker is completely before this run. This might be a marker that sits before the
     216            // first run we draw, or markers that were within runs we skipped due to truncation.
     217            continue;
     218        }
     219
     220        if (marker->startOffset() >= selectableRange.start + selectableRange.length) {
     221            // Marker is completely after this run, bail. A later run will paint it.
     222            break;
     223        }
     224
     225        // Marker intersects this run. Collect it.
     226        switch (marker->type()) {
     227        case DocumentMarker::Spelling:
     228        case DocumentMarker::CorrectionIndicator:
     229        case DocumentMarker::DictationAlternatives:
     230        case DocumentMarker::Grammar:
     231#if PLATFORM(IOS_FAMILY)
     232        // FIXME: See <rdar://problem/8933352>. Also, remove the PLATFORM(IOS_FAMILY)-guard.
     233        case DocumentMarker::DictationPhraseWithAlternatives:
     234#endif
     235        case DocumentMarker::TextMatch: {
     236            auto [clampedStart, clampedEnd] = selectableRange.clamp(marker->startOffset(), marker->endOffset());
     237            markedTexts.uncheckedAppend({ clampedStart, clampedEnd, markedTextTypeForMarkerType(marker->type()), marker });
     238            break;
     239        }
     240        case DocumentMarker::Replacement:
     241            break;
     242#if ENABLE(TELEPHONE_NUMBER_DETECTION)
     243        case DocumentMarker::TelephoneNumber:
     244            break;
     245#endif
     246        default:
     247            ASSERT_NOT_REACHED();
     248        }
     249    }
     250    return markedTexts;
     251}
     252
     253Vector<MarkedText> MarkedText::collectForDraggedContent(RenderText& renderer, const TextBoxSelectableRange& selectableRange)
     254{
     255    auto draggedContentRanges = renderer.draggedContentRangesBetweenOffsets(selectableRange.start, selectableRange.start + selectableRange.length);
     256
     257    return draggedContentRanges.map([&](const auto& range) -> MarkedText {
     258        return { selectableRange.clamp(range.first), selectableRange.clamp(range.second), MarkedText::DraggedContent };
     259    });
     260}
     261
     262}
  • trunk/Source/WebCore/rendering/MarkedText.h

    r270362 r278621  
    3131namespace WebCore {
    3232
     33class RenderBoxModelObject;
     34class RenderText;
    3335class RenderedDocumentMarker;
     36struct TextBoxSelectableRange;
    3437
    3538struct MarkedText {
     
    5356        DraggedContent,
    5457    };
     58
     59    enum class PaintPhase {
     60        Background,
     61        Foreground,
     62        Decoration
     63    };
     64
     65    enum class OverlapStrategy {
     66        None,
     67        Frontmost
     68    };
     69
    5570    unsigned startOffset;
    5671    unsigned endOffset;
     
    6580        return startOffset == other.startOffset && endOffset == other.endOffset && type == other.type && marker == other.marker && highlightName == other.highlightName;
    6681    }
     82
     83    WEBCORE_EXPORT static Vector<MarkedText> subdivide(const Vector<MarkedText>&, OverlapStrategy = OverlapStrategy::None);
     84
     85    static Vector<MarkedText> collectForDocumentMarkers(RenderText&, const TextBoxSelectableRange&, PaintPhase);
     86    static Vector<MarkedText> collectForHighlights(RenderText&, RenderBoxModelObject& parentRenderer, const TextBoxSelectableRange&, PaintPhase);
     87    static Vector<MarkedText> collectForDraggedContent(RenderText&, const TextBoxSelectableRange&);
    6788};
    68 
    69 enum class OverlapStrategy { None, Frontmost };
    70 WEBCORE_EXPORT Vector<MarkedText> subdivide(const Vector<MarkedText>&, OverlapStrategy = OverlapStrategy::None);
    7189
    7290}
  • trunk/Source/WebCore/rendering/MarkedTextStyle.cpp

    r274700 r278621  
    132132    }
    133133
    134     auto markedTexts = subdivide(textsToSubdivide);
     134    auto markedTexts = MarkedText::subdivide(textsToSubdivide);
    135135    ASSERT(!markedTexts.isEmpty());
    136136    if (UNLIKELY(markedTexts.isEmpty()))
  • trunk/Tools/ChangeLog

    r278616 r278621  
     12021-06-08  Antti Koivisto  <antti@apple.com>
     2
     3        Factor MarkedText collection out of LegacyInlineTextBox
     4        https://bugs.webkit.org/show_bug.cgi?id=226731
     5
     6        Reviewed by Sam Weinig.
     7
     8        * TestWebKitAPI/Tests/WebCore/MarkedText.cpp:
     9        (TestWebKitAPI::TEST):
     10
    1112021-06-08  Sam Weinig  <weinig@apple.com>
    212
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/MarkedText.cpp

    r270362 r278621  
    8181TEST(MarkedText, SubdivideEmpty)
    8282{
    83     EXPECT_EQ(0U, subdivide({ }).size());
    84     EXPECT_EQ(0U, subdivide({ }, OverlapStrategy::Frontmost).size());
     83    EXPECT_EQ(0U, MarkedText::subdivide({ }).size());
     84    EXPECT_EQ(0U, MarkedText::subdivide({ }, MarkedText::OverlapStrategy::Frontmost).size());
    8585}
    8686
     
    8888{
    8989    MarkedText markedText { 0, 9, MarkedText::SpellingError };
    90     auto results = subdivide({ markedText });
     90    auto results = MarkedText::subdivide({ markedText });
    9191    ASSERT_EQ(1U, results.size());
    9292    EXPECT_EQ(markedText, results[0]);
     
    100100        MarkedText { 22, 32, MarkedText::SpellingError },
    101101    };
    102     auto results = subdivide(expectedMarkedTexts);
     102    auto results = MarkedText::subdivide(expectedMarkedTexts);
    103103    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    104104    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     
    123123        MarkedText { 41, 45, MarkedText::SpellingError },
    124124    };
    125     auto results = subdivide(markedTexts);
     125    auto results = MarkedText::subdivide(markedTexts);
    126126    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    127127    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     
    144144        MarkedText { 41, 45, MarkedText::SpellingError },
    145145    };
    146     auto results = subdivide(markedTexts, OverlapStrategy::Frontmost);
     146    auto results = MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost);
    147147    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    148148    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     
    175175        MarkedText { 59, 63, MarkedText::GrammarError },
    176176    };
    177     auto results = subdivide(markedTexts, OverlapStrategy::Frontmost);
     177    auto results = MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost);
    178178    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    179179    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     
    196196        MarkedText { 50, 60, MarkedText::Selection },
    197197    };
    198     auto results = subdivide(markedTexts);
     198    auto results = MarkedText::subdivide(markedTexts);
    199199    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    200200    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     
    215215        MarkedText { 50, 60, MarkedText::Selection },
    216216    };
    217     auto results = subdivide(markedTexts, OverlapStrategy::Frontmost);
    218     ASSERT_EQ(expectedMarkedTexts.size(), results.size());
    219     for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
    220         EXPECT_EQ(expectedMarkedTexts[i], results[i]);
    221 }
    222 
    223 }
     217    auto results = MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost);
     218    ASSERT_EQ(expectedMarkedTexts.size(), results.size());
     219    for (size_t i = 0; i < expectedMarkedTexts.size(); ++i)
     220        EXPECT_EQ(expectedMarkedTexts[i], results[i]);
     221}
     222
     223}
Note: See TracChangeset for help on using the changeset viewer.