Skip to content

Commit

Permalink
Add priority for Highlight
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=257611
rdar://110125853

Reviewed by Megan Gardner.

Included implementation for priority and insertion order of css highlights.
Fixed selection inconsistency to always have active selection painted the same, above all markedTexts.
Fixed painting foreground color text so non-clashing styles of lower priority are still painted.
Added implementation for repainting when priority changes.
Added implementation for painting same semi-transparent overlapping highlight to be painted as a union.
Added a check if users assigned text color to take text color of prioritized highlight.

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/css/css-highlight-api/highlight-priority-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-highlight-api/highlight-priority-painting-expected.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-highlight-api/highlight-priority-painting-ref.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-highlight-api/highlight-priority-painting.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-highlight-api/highlight-priority.html: Added.
* Source/WebCore/Modules/highlight/Highlight.cpp:
(WebCore::Highlight::setPriority):
* Source/WebCore/Modules/highlight/Highlight.h:
(WebCore::Highlight::setPriority): Deleted.
* Source/WebCore/Modules/highlight/HighlightRegister.cpp:
(WebCore::HighlightRegister::setFromMapLike):
(WebCore::HighlightRegister::clear):
(WebCore::HighlightRegister::remove):
* Source/WebCore/Modules/highlight/HighlightRegister.h:
(WebCore::HighlightRegister::highlightNames const):
* Source/WebCore/rendering/MarkedText.cpp:
(WebCore::MarkedText::subdivide):
(WebCore::MarkedText::collectForHighlights):
* Source/WebCore/rendering/MarkedText.h:
(WebCore::MarkedText::MarkedText):
(WebCore::MarkedText::isHashTableDeletedValue const):
(WTF::add):
(WTF::HashTraits<WebCore::MarkedText>::constructDeletedValue):
(WTF::HashTraits<WebCore::MarkedText>::isDeletedValue):
(WTF::DefaultHash<WebCore::MarkedText>::hash):
(WTF::DefaultHash<WebCore::MarkedText>::equal):
(WebCore::MarkedText::operator== const): Deleted.
* Source/WebCore/rendering/StyledMarkedText.cpp:
(WebCore::resolveStyleForMarkedText):
(WebCore::coalesceAdjacentWithSameRanges):
(WebCore::orderHighlights):
(WebCore::StyledMarkedText::subdivideAndResolve):
(WebCore::StyledMarkedText::coalesceAdjacentWithEqualDecorations):
* Source/WebCore/rendering/TextBoxPainter.cpp:
(WebCore::TextBoxPainter<TextBoxPath>::paintForegroundAndDecorations):
* Source/WebCore/rendering/TextPaintStyle.h:

Canonical link: https://commits.webkit.org/265812@main
  • Loading branch information
jesxilin authored and rr-codes committed Jul 6, 2023
1 parent 0498413 commit 3b51039
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 27 deletions.
6 changes: 1 addition & 5 deletions LayoutTests/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -4910,20 +4910,16 @@ webkit.org/b/220325 http/wpt/css/css-highlight-api/highlight-text-cascade.html [
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-008.html [ Skip ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/css-target-text-decoration-001.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-002.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-004-2.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-009.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-014.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-below-selection.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-below-target-text.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-iframe-006.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-001.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-inheritance-002.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-003.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-005.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-invalidation-006.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-001.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-prioritization-002.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-staticrange-001.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-highlight-api/painting/custom-highlight-painting-017.html [ ImageOnlyFailure ]

http/tests/webgl/1.0.x/conformance/textures/misc/origin-clean-conformance-offscreencanvas.html [ Skip ]
http/tests/webgl/2.0.y/conformance/textures/misc/origin-clean-conformance-offscreencanvas.html [ Skip ]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Green Yellow Blue Yellow-Blue

PASS Highlight priority attribute is mutable

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>Highlight priority attribute painting</title>
<style>
#green-highlight {
background-color: green;
}
.yellow-highlight {
background-color: yellow;
}
.blue-highlight {
background-color: blue;
}
</style>
</head>
<body>
<span id="green-highlight">Green</span>
<span class="yellow-highlight">Yellow</span>
<span class="blue-highlight">Blue</span>
<span class="yellow-highlight">Yellow</span><span class="blue-highlight">-Blue</span>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>Highlight priority attribute painting</title>
<style>
#green-highlight {
background-color: green;
}
.yellow-highlight {
background-color: yellow;
}
.blue-highlight {
background-color: blue;
}
</style>
</head>
<body>
<span id="green-highlight">Green</span>
<span class="yellow-highlight">Yellow</span>
<span class="blue-highlight">Blue</span>
<span class="yellow-highlight">Yellow</span><span class="blue-highlight">-Blue</span>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<title>Highlight priority attribute painting correctness</title>
<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/#priorities">
<link rel="match" href="highlight-priority-painting-ref.html">
<style>
::highlight(yellow-highlight) {
background-color: yellow;
}
::highlight(green-highlight) {
background-color: green;
}
::highlight(blue-highlight) {
background-color: blue;
}
</style>
</head>
<body>
<span id="green-highlight">Green</span>
<span id="yellow-highlight">Yellow</span>
<span id="blue-highlight">Blue</span>
<span id="yellow-blue-highlight">Yellow-Blue</span>

<script>
let yellowBlue = document.getElementById("yellow-blue-highlight");
let green = document.getElementById("green-highlight");
let highlightGreen = new Highlight(new StaticRange({
startContainer: green.childNodes[0],
startOffset: 0,
endContainer: green.childNodes[0],
endOffset: 5
}));
let yellow = document.getElementById("yellow-highlight");
let highlightYellow = new Highlight(new StaticRange({
startContainer: yellow.childNodes[0],
startOffset: 0,
endContainer: yellow.childNodes[0],
endOffset: 6
}), new StaticRange({
startContainer: yellowBlue.childNodes[0],
startOffset: 0,
endContainer: yellowBlue.childNodes[0],
endOffset: 6
}));
let blue = document.getElementById("blue-highlight");
let highlightBlue = new Highlight(new StaticRange({
startContainer: blue.childNodes[0],
startOffset: 0,
endContainer: blue.childNodes[0],
endOffset: 4
}), new StaticRange({
startContainer: yellowBlue.childNodes[0],
startOffset: 0,
endContainer: yellowBlue.childNodes[0],
endOffset: 11
}));
CSS.highlights.set("yellow-highlight", highlightYellow);
CSS.highlights.set("green-highlight", highlightGreen);
CSS.highlights.set("blue-highlight", highlightBlue);
highlightYellow.priority = 10;
highlightBlue.priority = -1;
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<title>Highlight priority attribute is mutable</title>
<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/#priorities">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
::highlight(yellow-highlight) {
background-color: yellow;
}
::highlight(green-highlight) {
background-color: green;
}
::highlight(blue-highlight) {
background-color: blue;
}
</style>
</head>
<body>
<span id="green-highlight">Green</span>
<span id="yellow-highlight">Yellow</span>
<span id="blue-highlight">Blue</span>
<span id="yellow-blue-highlight">Yellow-Blue</span>

<script>
test(() => {
let yellowBlue = document.getElementById("yellow-blue-highlight");

let green = document.getElementById("green-highlight");
let highlightGreen = new Highlight(new StaticRange({
startContainer: green.childNodes[0],
startOffset: 0,
endContainer: green.childNodes[0],
endOffset: 6
}));

let yellow = document.getElementById("yellow-highlight");
let highlightYellow = new Highlight(new StaticRange({
startContainer: yellow.childNodes[0],
startOffset: 0,
endContainer: yellow.childNodes[0],
endOffset: 6
}), new StaticRange({
startContainer: yellowBlue.childNodes[0],
startOffset: 0,
endContainer: yellowBlue.childNodes[0],
endOffset: 6
}));

let blue = document.getElementById("blue-highlight");
let highlightBlue = new Highlight(new StaticRange({
startContainer: blue.childNodes[0],
startOffset: 0,
endContainer: blue.childNodes[0],
endOffset: 4
}), new StaticRange({
startContainer: yellowBlue.childNodes[0],
startOffset: 0,
endContainer: yellowBlue.childNodes[0],
endOffset: 11
}));

CSS.highlights.set("yellow-highlight", highlightYellow);
CSS.highlights.set("green-highlight", highlightGreen);
CSS.highlights.set("blue-highlight", highlightBlue);

highlightYellow.priority = 10;
highlightBlue.priority = -1;

assert_equals(highlightYellow.priority, 10);
assert_equals(highlightGreen.priority, 0);
assert_equals(highlightBlue.priority, -1);
});
</script>

</body>
</html>
9 changes: 8 additions & 1 deletion Source/WebCore/Modules/highlight/Highlight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,12 @@ void Highlight::repaint()
repaintRange(data->range());
}

} // namespace WebCore
void Highlight::setPriority(int priority)
{
if (m_priority == priority)
return;
m_priority = priority;
repaint();
}

} // namespace WebCore
2 changes: 1 addition & 1 deletion Source/WebCore/Modules/highlight/Highlight.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Highlight : public RefCounted<Highlight> {
void setType(Type type) { m_type = type; }

int priority() const { return m_priority; }
void setPriority(int priority) { m_priority = priority; }
void setPriority(int);

void repaint();
const Vector<Ref<HighlightRangeData>>& rangesData() const { return m_rangesData; }
Expand Down
8 changes: 7 additions & 1 deletion Source/WebCore/Modules/highlight/HighlightRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,22 @@ void HighlightRegister::initializeMapLike(DOMMapAdapter& map)

void HighlightRegister::setFromMapLike(AtomString&& key, Ref<Highlight>&& value)
{
m_map.set(WTFMove(key), WTFMove(value));
auto addResult = m_map.set(key, WTFMove(value));
if (addResult.isNewEntry) {
ASSERT(!m_highlightNames.contains(key));
m_highlightNames.append(WTFMove(key));
}
}

void HighlightRegister::clear()
{
m_map.clear();
m_highlightNames.clear();
}

bool HighlightRegister::remove(const AtomString& key)
{
m_highlightNames.removeFirst(key);
return m_map.remove(key);
}
#if ENABLE(APP_HIGHLIGHTS)
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/Modules/highlight/HighlightRegister.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ class HighlightRegister : public RefCounted<HighlightRegister> {

WEBCORE_EXPORT void addAnnotationHighlightWithRange(Ref<StaticRange>&&);
const HashMap<AtomString, Ref<Highlight>>& map() const { return m_map; }
const Vector<AtomString>& highlightNames() const { return m_highlightNames; }

private:
HighlightRegister() = default;
HashMap<AtomString, Ref<Highlight>> m_map;
Vector<AtomString> m_highlightNames;

HighlightVisibility m_highlightVisibility { HighlightVisibility::Hidden };
};
Expand Down
31 changes: 25 additions & 6 deletions Source/WebCore/rendering/MarkedText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Vector<MarkedText> MarkedText::subdivide(const Vector<MarkedText>& markedTexts,
// The appended marked texts may not be in paint order. We will fix this up at the end of this function.
for (unsigned j = 0; j < i; ++j) {
if (!processedMarkedTexts.contains(offsets[j].markedText))
result.append({ offsetSoFar, offsets[i].value, offsets[j].markedText->type, offsets[j].markedText->marker, offsets[j].markedText->highlightName });
result.append({ offsetSoFar, offsets[i].value, offsets[j].markedText->type, offsets[j].markedText->marker, offsets[j].markedText->highlightName, offsets[j].markedText->priority });
}
}
offsetSoFar = offsets[i].value;
Expand All @@ -113,19 +113,38 @@ Vector<MarkedText> MarkedText::collectForHighlights(const RenderText& renderer,
auto& parentRenderer = *renderer.parent();
auto& parentStyle = parentRenderer.style();
if (auto highlightRegister = renderer.document().highlightRegisterIfExists()) {
for (auto& highlight : highlightRegister->map()) {
auto renderStyle = parentRenderer.getUncachedPseudoStyle({ PseudoId::Highlight, highlight.key }, &parentStyle);
for (auto& highlightName : highlightRegister->highlightNames()) {
auto renderStyle = parentRenderer.getUncachedPseudoStyle({ PseudoId::Highlight, highlightName }, &parentStyle);
if (!renderStyle)
continue;
if (renderStyle->textDecorationsInEffect().isEmpty() && phase == PaintPhase::Decoration)
continue;
for (auto& rangeData : highlight.value->rangesData()) {
for (auto& rangeData : highlightRegister->map().get(highlightName)->rangesData()) {
if (!highlightData.setRenderRange(rangeData))
continue;

auto [highlightStart, highlightEnd] = highlightData.rangeForTextBox(renderer, selectableRange);
if (highlightStart < highlightEnd)
markedTexts.append({ highlightStart, highlightEnd, MarkedText::Type::Highlight, nullptr, highlight.key });

if (highlightStart < highlightEnd) {
int currentPriority = highlightRegister->map().get(highlightName)->priority();
// If we can just append it to the end, do that instead.
if (markedTexts.isEmpty() || markedTexts.last().priority <= currentPriority)
markedTexts.append({ highlightStart, highlightEnd, MarkedText::Type::Highlight, nullptr, highlightName, currentPriority });
else {
// Find the first correct place to insert highlight.
bool wasInserted = false;
for (int index = markedTexts.size() - 1; index >= 0; index--) {
if (markedTexts[index].priority <= currentPriority) {
markedTexts.insert(index + 1, { highlightStart, highlightEnd, MarkedText::Type::Highlight, nullptr, highlightName, currentPriority });
wasInserted = true;
break;
}
}
// Insert at front of vector if lower priority than everything in markedTexts.
if (!wasInserted)
markedTexts.insert(0, { highlightStart, highlightEnd, MarkedText::Type::Highlight, nullptr, highlightName, currentPriority });
}
}
}
}
}
Expand Down
Loading

0 comments on commit 3b51039

Please sign in to comment.