Changeset 253857 in webkit
- Timestamp:
- Dec 20, 2019, 5:33:10 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 13 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/imported/w3c/ChangeLog
r253855 r253857 1 2019-12-20 Megan Gardner <megan_gardner@apple.com> 2 3 Paint highlights specified in CSS Highlight API 4 https://bugs.webkit.org/show_bug.cgi?id=205318 5 6 Reviewed by Ryosuke Niwa. 7 8 * web-platform-tests/css/css-highlight-api/highlight-text-across-elements-expected.html: Added. 9 * web-platform-tests/css/css-highlight-api/highlight-text-across-elements.html: Added. 10 * web-platform-tests/css/css-highlight-api/highlight-text-expected.html: Added. 11 * web-platform-tests/css/css-highlight-api/highlight-text.html: Added. 12 1 13 2019-12-20 Chris Dumez <cdumez@apple.com> 2 14 -
trunk/Source/WebCore/ChangeLog
r253856 r253857 1 2019-12-20 Megan Gardner <megan_gardner@apple.com> 2 3 Paint highlights specified in CSS Highlight API 4 https://bugs.webkit.org/show_bug.cgi?id=205318 5 6 Reviewed by Ryosuke Niwa. 7 8 Render highlights when present, similar to the way we render selection. 9 10 Tests: imported/w3c/web-platform-tests/css/css-highlight-api/highlight-text-across-elements.html 11 imported/w3c/web-platform-tests/css/css-highlight-api/highlight-text.html 12 13 * Modules/highlight/HighlightMap.h: 14 (WebCore::HighlightMap::map const): 15 16 Add a getter for the internal HashMap. 17 18 * rendering/InlineTextBox.cpp: 19 (WebCore::InlineTextBox::selectionState): 20 (WebCore::InlineTextBox::verifySelectionState const): 21 (WebCore::InlineTextBox::paint): 22 (WebCore::InlineTextBox::clampedStartEndForState const): 23 (WebCore::InlineTextBox::selectionStartEnd const): 24 (WebCore::InlineTextBox::highlightStartEnd const): 25 (WebCore::InlineTextBox::resolveStyleForMarkedText): 26 27 Use the highlight name from the HighlightRangeGroup to obtain the style from the renderer. 28 29 (WebCore::InlineTextBox::collectMarkedTextsForHighlights const): 30 31 Render the highlights when painting text. Determine if a highlight is present in the current RenderObject, and 32 add additional MarkedText to be rendered when painting 33 34 * rendering/InlineTextBox.h: 35 * rendering/MarkedText.cpp: 36 (WebCore::subdivide): 37 * rendering/MarkedText.h: 38 (WebCore::MarkedText::operator== const): 39 40 Expand MarkedText to take a style name. 41 42 * rendering/SelectionRangeData.cpp: 43 (WebCore::SelectionRangeData::setContext): 44 (WebCore::SelectionRangeData::selectionStateForRenderer): 45 (WebCore::SelectionRangeData::set): 46 * rendering/SelectionRangeData.h: 47 48 Leverage SelectionRangeData for highlights. 49 1 50 2019-12-20 Chris Dumez <cdumez@apple.com> 2 51 -
trunk/Source/WebCore/Modules/highlight/HighlightMap.h
r253309 r253857 46 46 47 47 RefPtr<HighlightRangeGroup> getGroupForKey(const String& key); 48 const HashMap<String, Ref<HighlightRangeGroup>>& map() const { return m_map; } 48 49 49 50 private: -
trunk/Source/WebCore/dom/Document.cpp
r253653 r253857 780 780 781 781 clearScriptedAnimationController(); 782 783 if (m_highlightMap) 784 m_highlightMap->clear(); 782 785 783 786 m_pendingScrollEventTargetList = nullptr; -
trunk/Source/WebCore/rendering/InlineTextBox.cpp
r250341 r253857 29 29 #include "DocumentMarkerController.h" 30 30 #include "Editor.h" 31 #include "ElementRuleCollector.h" 31 32 #include "EllipsisBox.h" 32 33 #include "EventRegion.h" 33 34 #include "Frame.h" 34 35 #include "GraphicsContext.h" 36 #include "HighlightMap.h" 35 37 #include "HitTestResult.h" 36 38 #include "ImageBuffer.h" … … 47 49 #include "RenderView.h" 48 50 #include "RenderedDocumentMarker.h" 51 #include "RuntimeEnabledFeatures.h" 52 #include "SelectionRangeData.h" 49 53 #include "Text.h" 50 54 #include "TextDecorationPainter.h" … … 153 157 RenderObject::SelectionState InlineTextBox::selectionState() 154 158 { 155 RenderObject::SelectionState state = renderer().selectionState(); 159 auto state = verifySelectionState(renderer().selectionState(), renderer().view().selection()); 160 161 // FIXME: this code mutates selection state, but it's used at a simple getter elsewhere 162 // in this file. This code should likely live in SelectionRangeData, or somewhere else. 163 // <rdar://problem/58125978> 164 // https://bugs.webkit.org/show_bug.cgi?id=205528 165 // If there are ellipsis following, make sure their selection is updated. 166 if (m_truncation != cNoTruncation && root().ellipsisBox()) { 167 EllipsisBox* ellipsis = root().ellipsisBox(); 168 if (state != RenderObject::SelectionNone) { 169 auto [selectionStart, selectionEnd] = selectionStartEnd(); 170 // The ellipsis should be considered to be selected if the end of 171 // the selection is past the beginning of the truncation and the 172 // beginning of the selection is before or at the beginning of the 173 // truncation. 174 ellipsis->setSelectionState(selectionEnd >= m_truncation && selectionStart <= m_truncation ? 175 RenderObject::SelectionInside : RenderObject::SelectionNone); 176 } else 177 ellipsis->setSelectionState(RenderObject::SelectionNone); 178 } 179 180 return state; 181 } 182 183 RenderObject::SelectionState InlineTextBox::verifySelectionState(RenderObject::SelectionState state, SelectionRangeData& selection) const 184 { 156 185 if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) { 157 auto& selection = renderer().view().selection();158 186 auto startPos = selection.startPosition(); 159 187 auto endPos = selection.endPosition(); … … 175 203 else if (state == RenderObject::SelectionBoth) 176 204 state = RenderObject::SelectionNone; 177 }178 179 // If there are ellipsis following, make sure their selection is updated.180 if (m_truncation != cNoTruncation && root().ellipsisBox()) {181 EllipsisBox* ellipsis = root().ellipsisBox();182 if (state != RenderObject::SelectionNone) {183 auto [selectionStart, selectionEnd] = selectionStartEnd();184 // The ellipsis should be considered to be selected if the end of185 // the selection is past the beginning of the truncation and the186 // beginning of the selection is before or at the beginning of the187 // truncation.188 ellipsis->setSelectionState(selectionEnd >= m_truncation && selectionStart <= m_truncation ?189 RenderObject::SelectionInside : RenderObject::SelectionNone);190 } else191 ellipsis->setSelectionState(RenderObject::SelectionNone);192 205 } 193 206 … … 525 538 526 539 Vector<MarkedText> markedTexts = collectMarkedTextsForDocumentMarkers(TextPaintPhase::Background); 540 auto highlightMarkedTexts = collectMarkedTextsForHighlights(TextPaintPhase::Background); 541 if (!highlightMarkedTexts.isEmpty()) 542 markedTexts.appendVector(WTFMove(highlightMarkedTexts)); 527 543 #if ENABLE(TEXT_SELECTION) 528 544 if (haveSelection && !useCustomUnderlines && !context.paintingDisabled()) { … … 558 574 if (!isPrinting) { 559 575 markedTexts.appendVector(collectMarkedTextsForDocumentMarkers(TextPaintPhase::Foreground)); 576 auto highlightMarkedTexts = collectMarkedTextsForHighlights(TextPaintPhase::Foreground); 577 if (!highlightMarkedTexts.isEmpty()) 578 markedTexts.appendVector(WTFMove(highlightMarkedTexts)); 560 579 561 580 bool shouldPaintDraggedContent = !(paintInfo.paintBehavior.contains(PaintBehavior::ExcludeSelection)); … … 653 672 } 654 673 655 std::pair<unsigned, unsigned> InlineTextBox::selectionStartEnd() const 656 { 657 auto selectionState = renderer().selectionState(); 674 std::pair<unsigned, unsigned> InlineTextBox::clampedStartEndForState(unsigned start, unsigned end, RenderObject::SelectionState selectionState) const 675 { 658 676 if (selectionState == RenderObject::SelectionInside) 659 677 return { 0, clampedOffset(m_start + m_len) }; 660 678 661 auto start = renderer().view().selection().startPosition();662 auto end = renderer().view().selection().endPosition();663 679 if (selectionState == RenderObject::SelectionStart) 664 680 end = renderer().text().length(); … … 666 682 start = 0; 667 683 return { clampedOffset(start), clampedOffset(end) }; 684 } 685 686 std::pair<unsigned, unsigned> InlineTextBox::selectionStartEnd() const 687 { 688 auto selectionState = renderer().selectionState(); 689 690 return clampedStartEndForState(renderer().view().selection().startPosition(), renderer().view().selection().endPosition(), selectionState); 691 } 692 693 std::pair<unsigned, unsigned> InlineTextBox::highlightStartEnd(SelectionRangeData &rangeData) const 694 { 695 auto state = rangeData.selectionStateForRenderer(renderer()); 696 state = verifySelectionState(state, rangeData); 697 698 if (state == RenderObject::SelectionNone) 699 return {0, 0}; 700 701 return clampedStartEndForState(rangeData.startPosition(), rangeData.endPosition(), state); 668 702 } 669 703 … … 770 804 case MarkedText::SpellingError: 771 805 case MarkedText::Unmarked: 806 break; 807 case MarkedText::Highlight: 808 if (auto renderStyle = parent()->renderer().getUncachedPseudoStyle({ PseudoId::Highlight, markedText.highlightName }, &parent()->renderer().style())) { 809 style.backgroundColor = renderStyle->backgroundColor(); 810 style.textStyles.fillColor = renderStyle->computedStrokeColor(); 811 style.textStyles.strokeColor = renderStyle->computedStrokeColor(); 812 813 auto color = renderStyle->visitedDependentColorWithColorFilter(CSSPropertyWebkitTextFillColor); 814 auto decorationStyle = renderStyle->textDecorationStyle(); 815 auto decorations = renderStyle->textDecorationsInEffect(); 816 817 if (decorations.containsAny({ TextDecoration::Underline, TextDecoration::Overline, TextDecoration::LineThrough })) { 818 style.textDecorationStyles.underlineColor = color; 819 style.textDecorationStyles.underlineStyle = decorationStyle; 820 } 821 } 772 822 break; 773 823 case MarkedText::DraggedContent: … … 964 1014 } 965 1015 1016 1017 Vector<MarkedText> InlineTextBox::collectMarkedTextsForHighlights(TextPaintPhase phase) const 1018 { 1019 if (!RuntimeEnabledFeatures::sharedFeatures().highlightAPIEnabled()) 1020 return { }; 1021 ASSERT_ARG(phase, phase == TextPaintPhase::Background || phase == TextPaintPhase::Foreground || phase == TextPaintPhase::Decoration); 1022 UNUSED_PARAM(phase); 1023 if (!renderer().textNode()) 1024 return { }; 1025 1026 Vector<MarkedText> markedTexts; 1027 auto& parentRenderer = parent()->renderer(); 1028 auto& parentStyle = parentRenderer.style(); 1029 for (auto& [highlightKey, highlightGroup] : renderer().document().highlightMap().map()) { 1030 auto renderStyle = parentRenderer.getUncachedPseudoStyle({ PseudoId::Highlight, highlightKey }, &parentStyle); 1031 if (!renderStyle) 1032 continue; 1033 for (auto& staticRange : highlightGroup->ranges()) { 1034 Position startPos = createLegacyEditingPosition(staticRange->startContainer(), staticRange->startOffset()); 1035 Position endPos = createLegacyEditingPosition(staticRange->endContainer(), staticRange->endOffset()); 1036 1037 if (startPos.isNotNull() && endPos.isNotNull()) { 1038 RenderObject* startRenderer = startPos.deprecatedNode()->renderer(); 1039 int startOffset = startPos.deprecatedEditingOffset(); 1040 RenderObject* endRenderer = endPos.deprecatedNode()->renderer(); 1041 int endOffset = endPos.deprecatedEditingOffset(); 1042 ASSERT(startOffset >= 0 && endOffset >= 0); 1043 if (!startRenderer || !endRenderer) 1044 continue; 1045 auto highlightData = SelectionRangeData(renderer().view()); 1046 highlightData.setContext({startRenderer, endRenderer, static_cast<unsigned>(startOffset), static_cast<unsigned>(endOffset)}); 1047 auto [highlightStart, highlightEnd] = highlightStartEnd(highlightData); 1048 if (highlightStart < highlightEnd) 1049 markedTexts.append({ highlightStart, highlightEnd, MarkedText::Highlight, nullptr, highlightKey }); 1050 } 1051 } 1052 } 1053 return markedTexts; 1054 } 1055 966 1056 FloatPoint InlineTextBox::textOriginFromBoxRect(const FloatRect& boxRect) const 967 1057 { -
trunk/Source/WebCore/rendering/InlineTextBox.h
r249160 r253857 122 122 bool isSelected(unsigned startPosition, unsigned endPosition) const; 123 123 std::pair<unsigned, unsigned> selectionStartEnd() const; 124 std::pair<unsigned, unsigned> highlightStartEnd(SelectionRangeData&) const; 124 125 125 126 protected: … … 133 134 void extractLine() final; 134 135 void attachLine() final; 136 137 RenderObject::SelectionState verifySelectionState(RenderObject::SelectionState, SelectionRangeData&) const; 138 std::pair<unsigned, unsigned> clampedStartEndForState(unsigned, unsigned, RenderObject::SelectionState) const; 135 139 136 140 public: … … 170 174 Vector<MarkedText> collectMarkedTextsForDraggedContent(); 171 175 Vector<MarkedText> collectMarkedTextsForDocumentMarkers(TextPaintPhase) const; 176 Vector<MarkedText> collectMarkedTextsForHighlights(TextPaintPhase) const; 172 177 173 178 MarkedTextStyle computeStyleForUnmarkedMarkedText(const PaintInfo&) const; -
trunk/Source/WebCore/rendering/MarkedText.cpp
r239427 r253857 75 75 } 76 76 if (frontmost) 77 result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].markedText->type, offsets[*frontmost].markedText->marker });77 result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].markedText->type, offsets[*frontmost].markedText->marker, offsets[*frontmost].markedText->highlightName }); 78 78 } else { 79 79 // The appended marked texts may not be in paint order. We will fix this up at the end of this function. 80 80 for (unsigned j = 0; j < i; ++j) { 81 81 if (!processedMarkedTexts.contains(offsets[j].markedText)) 82 result.append({ offsetSoFar, offsets[i].value, offsets[j].markedText->type, offsets[j].markedText->marker });82 result.append({ offsetSoFar, offsets[i].value, offsets[j].markedText->type, offsets[j].markedText->marker, offsets[j].markedText->highlightName }); 83 83 } 84 84 } -
trunk/Source/WebCore/rendering/MarkedText.h
r237266 r253857 27 27 28 28 #include <wtf/Vector.h> 29 #include <wtf/text/WTFString.h> 29 30 30 31 namespace WebCore { … … 41 42 TextMatch, 42 43 DictationAlternatives, 44 Highlight, 43 45 #if PLATFORM(IOS_FAMILY) 44 46 // FIXME: See <rdar://problem/8933352>. Also, remove the PLATFORM(IOS_FAMILY)-guard. … … 52 54 Type type; 53 55 const RenderedDocumentMarker* marker { nullptr }; 56 String highlightName { }; 54 57 55 58 bool isEmpty() const { return endOffset <= startOffset; } … … 57 60 bool operator==(const MarkedText& other) const 58 61 { 59 return startOffset == other.startOffset && endOffset == other.endOffset && type == other.type && marker == other.marker ;62 return startOffset == other.startOffset && endOffset == other.endOffset && type == other.type && marker == other.marker && highlightName == other.highlightName; 60 63 } 61 64 }; -
trunk/Source/WebCore/rendering/SelectionRangeData.cpp
r248846 r253857 155 155 } 156 156 157 void SelectionRangeData::setContext(const Context& context) 158 { 159 ASSERT(context.start() && context.end()); 160 m_selectionContext = context; 161 } 162 163 RenderObject::SelectionState SelectionRangeData::selectionStateForRenderer(RenderObject& renderer) 164 { 165 // FIXME: we shouldln't have to check that a renderer is a descendant of the render node 166 // from the range. This is likely because we aren't using VisiblePositions yet. 167 // Planned fix in a followup: <rdar://problem/58095923> 168 // https://bugs.webkit.org/show_bug.cgi?id=205529 169 170 if (&renderer == m_selectionContext.start() || renderer.isDescendantOf(m_selectionContext.start())) { 171 if (m_selectionContext.start() && m_selectionContext.end() && m_selectionContext.start() == m_selectionContext.end()) 172 return RenderObject::SelectionBoth; 173 if (m_selectionContext.start()) 174 return RenderObject::SelectionStart; 175 } 176 if (&renderer == m_selectionContext.end() || renderer.isDescendantOf(m_selectionContext.end())) 177 return RenderObject::SelectionEnd; 178 179 RenderObject* selectionEnd = nullptr; 180 auto* selectionDataEnd = m_selectionContext.end(); 181 if (selectionDataEnd) 182 selectionEnd = rendererAfterPosition(*selectionDataEnd, m_selectionContext.endPosition().value()); 183 SelectionIterator selectionIterator(m_selectionContext.start()); 184 for (auto* currentRenderer = m_selectionContext.start(); currentRenderer && currentRenderer != m_selectionContext.end(); currentRenderer = selectionIterator.next()) { 185 if (currentRenderer == m_selectionContext.start() || currentRenderer == m_selectionContext.end()) 186 continue; 187 if (!currentRenderer->canBeSelectionLeaf()) 188 continue; 189 if (&renderer == currentRenderer) 190 return RenderObject::SelectionInside; 191 } 192 return RenderObject::SelectionNone; 193 194 } 195 157 196 void SelectionRangeData::set(const Context& selection, RepaintMode blockRepaintMode) 158 197 { 159 // Make sure both our start and end objects are defined.160 // Check www.msnbc.com and try clicking around to find the case where this happened.161 198 if ((selection.start() && !selection.end()) || (selection.end() && !selection.start())) 162 199 return; -
trunk/Source/WebCore/rendering/SelectionRangeData.h
r243844 r253857 72 72 Optional<unsigned> m_endPosition; 73 73 }; 74 74 75 void setContext(const Context&); 76 75 77 enum class RepaintMode { NewXOROld, NewMinusOld, Nothing }; 76 78 void set(const Context&, RepaintMode = RepaintMode::NewXOROld); … … 87 89 IntRect boundsClippedToVisibleContent() const { return collectBounds(ClipToVisibleContent::Yes); } 88 90 void repaint() const; 91 92 RenderObject::SelectionState selectionStateForRenderer(RenderObject&); 89 93 90 94 private: -
trunk/Tools/ChangeLog
r253845 r253857 1 2019-12-20 Megan Gardner <megan_gardner@apple.com> 2 3 Paint highlights specified in CSS Highlight API 4 https://bugs.webkit.org/show_bug.cgi?id=205318 5 6 Reviewed by Ryosuke Niwa. 7 8 Expand MarkedText to take a style name. 9 10 * TestWebKitAPI/Tests/WebCore/MarkedText.cpp: 11 (WebCore::operator<<): 12 1 13 2019-12-20 Jonathan Bedard <jbedard@apple.com> 2 14 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/MarkedText.cpp
r237266 r253857 56 56 case MarkedText::TextMatch: 57 57 return os << "TextMatch"; 58 case MarkedText::Highlight: 59 return os << "Highlight"; 58 60 case MarkedText::Unmarked: 59 61 return os << "Unmarked";
Note:
See TracChangeset
for help on using the changeset viewer.