Diff
Modified: trunk/Source/WebCore/ChangeLog (278544 => 278545)
--- trunk/Source/WebCore/ChangeLog 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/ChangeLog 2021-06-07 06:19:03 UTC (rev 278545)
@@ -1,3 +1,45 @@
+2021-06-06 Antti Koivisto <[email protected]>
+
+ Factor selection clamping into a type
+ https://bugs.webkit.org/show_bug.cgi?id=226697
+
+ Reviewed by Sam Weinig.
+
+ TextBoxSelectableRange will be helpful for moving selection code out of the legacy inline boxes.
+ It also allows some code sharing already in this patch.
+
+ * Headers.cmake:
+ * WebCore.xcodeproj/project.pbxproj:
+ * layout/integration/LayoutIntegrationRunIteratorLegacyPath.h:
+ (WebCore::LayoutIntegration::RunIteratorLegacyPath::isSelectable const):
+ * layout/integration/LayoutIntegrationRunIteratorModernPath.h:
+ (WebCore::LayoutIntegration::RunIteratorModernPath::positionForOffset const):
+ (WebCore::LayoutIntegration::RunIteratorModernPath::isSelectable const):
+ (WebCore::LayoutIntegration::RunIteratorModernPath::selectionRect const):
+ (WebCore::LayoutIntegration::RunIteratorModernPath::selectableRange const):
+ (WebCore::LayoutIntegration::RunIteratorModernPath::clampedOffset const): Deleted.
+ * rendering/LegacyInlineTextBox.cpp:
+ (WebCore::LegacyInlineTextBox::isSelectable const):
+ (WebCore::LegacyInlineTextBox::localSelectionRect const):
+ (WebCore::LegacyInlineTextBox::paint):
+ (WebCore::LegacyInlineTextBox::selectableRange const):
+ (WebCore::LegacyInlineTextBox::clampedStartEndForState const):
+ (WebCore::LegacyInlineTextBox::calculateDocumentMarkerBounds const):
+ (WebCore::LegacyInlineTextBox::collectMarkedTextsForDraggedContent):
+ (WebCore::LegacyInlineTextBox::collectMarkedTextsForDocumentMarkers const):
+ (WebCore::LegacyInlineTextBox::paintCompositionBackground):
+ (WebCore::LegacyInlineTextBox::positionForOffset const):
+ (WebCore::LegacyInlineTextBox::isSelected const): Deleted.
+ (WebCore::LegacyInlineTextBox::clampedOffset const): Deleted.
+ * rendering/LegacyInlineTextBox.h:
+ * rendering/RenderBlockFlow.cpp:
+ (WebCore::RenderBlockFlow::inlineSelectionGaps):
+ * rendering/TextBoxSelectableRange.h: Added.
+ (WebCore::TextBoxSelectableRange::clamp const):
+ (WebCore::TextBoxSelectableRange::intersects const):
+ * rendering/svg/SVGInlineTextBox.cpp:
+ (WebCore::SVGInlineTextBox::localSelectionRect const):
+
2021-06-06 Chris Dumez <[email protected]>
Drop MainThreadTaskDispatcher and use callOnMainThread() instead
Modified: trunk/Source/WebCore/Headers.cmake (278544 => 278545)
--- trunk/Source/WebCore/Headers.cmake 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/Headers.cmake 2021-06-07 06:19:03 UTC (rev 278545)
@@ -1580,6 +1580,7 @@
rendering/RenderWidget.h
rendering/ScrollAlignment.h
rendering/SelectionRangeData.h
+ rendering/TextBoxSelectableRange.h
rendering/line/LineWidth.h
rendering/line/TrailingObjects.h
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (278544 => 278545)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-06-07 06:19:03 UTC (rev 278545)
@@ -5212,6 +5212,7 @@
E446143A0CD689C800FADA75 /* JSHTMLMediaElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E4B423800CBFB73C00AF2ECE /* JSHTMLMediaElement.h */; };
E446143C0CD689CC00FADA75 /* JSHTMLSourceElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E4B423720CBFB6E000AF2ECE /* JSHTMLSourceElement.h */; };
E44614520CD68A3500FADA75 /* RenderVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = E4B41E340CBFB60900AF2ECE /* RenderVideo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ E447F5B3266CF63D00133F00 /* TextBoxSelectableRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E447F5B1266CF63D00133F00 /* TextBoxSelectableRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
E44B4BB4141650D7002B1D8B /* SelectorChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = E44B4BB2141650D7002B1D8B /* SelectorChecker.h */; };
E44FA1851BCA6B5A0091B6EF /* ComposedTreeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E44FA1841BCA6B5A0091B6EF /* ComposedTreeIterator.h */; };
E451C6312394027900993190 /* LayoutUnits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F73918C2106CEDD006AF262 /* LayoutUnits.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -16564,6 +16565,7 @@
E44614110CD6826900FADA75 /* JSMediaError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMediaError.h; sourceTree = "<group>"; };
E44614120CD6826900FADA75 /* JSTimeRanges.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTimeRanges.cpp; sourceTree = "<group>"; };
E44614130CD6826900FADA75 /* JSTimeRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTimeRanges.h; sourceTree = "<group>"; };
+ E447F5B1266CF63D00133F00 /* TextBoxSelectableRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextBoxSelectableRange.h; sourceTree = "<group>"; };
E44B4BB1141650D7002B1D8B /* SelectorChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectorChecker.cpp; sourceTree = "<group>"; };
E44B4BB2141650D7002B1D8B /* SelectorChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectorChecker.h; sourceTree = "<group>"; };
E44EE3A617576E5500EEE8CF /* FontGenericFamilies.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FontGenericFamilies.cpp; sourceTree = "<group>"; };
@@ -30409,6 +30411,7 @@
A8CFF04C0A154F09000A4234 /* TableLayout.h */,
0F54DCE31881051D003EEDBB /* TextAutoSizing.cpp */,
0F54DCE41881051D003EEDBB /* TextAutoSizing.h */,
+ E447F5B1266CF63D00133F00 /* TextBoxSelectableRange.h */,
582DE3221C30C85400BE02A8 /* TextDecorationPainter.cpp */,
582DE3231C30C85400BE02A8 /* TextDecorationPainter.h */,
1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */,
@@ -32468,6 +32471,7 @@
41FABD2D1F4DFE4A006A6C97 /* DOMCacheEngine.h in Headers */,
41380C291F3436AC00155FDA /* DOMCacheStorage.h in Headers */,
4BDA3FFE2151B6F500FD6604 /* DOMCSSCustomPropertyDescriptor.h in Headers */,
+ E447F5B3266CF63D00133F00 /* TextBoxSelectableRange.h in Headers */,
FC9A0F75164094CF003D6B8D /* DOMCSSNamespace.h in Headers */,
4B6B5CBD21640EFF00603817 /* DOMCSSPaintWorklet.h in Headers */,
4BDA3FFF2151B6F500FD6604 /* DOMCSSRegisterCustomProperty.h in Headers */,
Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorLegacyPath.h (278544 => 278545)
--- trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorLegacyPath.h 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorLegacyPath.h 2021-06-07 06:19:03 UTC (rev 278545)
@@ -74,7 +74,7 @@
unsigned offsetForPosition(float x) const { return inlineTextBox()->offsetForPosition(x); }
float positionForOffset(unsigned offset) const { return inlineTextBox()->positionForOffset(offset); }
- bool isSelectable(unsigned start, unsigned end) const { return inlineTextBox()->isSelected(start, end); }
+ bool isSelectable(unsigned start, unsigned end) const { return inlineTextBox()->isSelectable(start, end); }
LayoutRect selectionRect(unsigned start, unsigned end) const { return inlineTextBox()->localSelectionRect(start, end); }
const RenderObject& renderer() const
Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h (278544 => 278545)
--- trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h 2021-06-07 06:19:03 UTC (rev 278545)
@@ -29,6 +29,7 @@
#include "FontCascade.h"
#include "LayoutIntegrationInlineContent.h"
+#include "TextBoxSelectableRange.h"
namespace WebCore {
@@ -91,7 +92,7 @@
if (isLineBreak())
return rect().x();
- auto endOffset = clampedOffset(offset);
+ auto endOffset = selectableRange().clamp(offset);
LayoutRect selectionRect = LayoutRect(rect().x(), 0, 0, 0);
TextRun textRun = createTextRun(HyphenMode::Ignore);
@@ -101,13 +102,12 @@
bool isSelectable(unsigned start, unsigned end) const
{
- return clampedOffset(start) < clampedOffset(end);
+ return selectableRange().intersects(start, end);
}
LayoutRect selectionRect(unsigned rangeStart, unsigned rangeEnd) const
{
- unsigned clampedStart = clampedOffset(rangeStart);
- unsigned clampedEnd = clampedOffset(rangeEnd);
+ auto [clampedStart, clampedEnd] = selectableRange().clamp(rangeStart, rangeEnd);
if (clampedStart >= clampedEnd && !(rangeStart == rangeEnd && rangeStart >= start() && rangeStart <= end()))
return { };
@@ -204,14 +204,13 @@
private:
friend class RunIterator;
- unsigned clampedOffset(unsigned offset) const
+ TextBoxSelectableRange selectableRange() const
{
- auto clampedOffset = std::max(start(), std::min(offset, end())) - start();
- // We treat the last codepoint in this run and the hyphen as a single unit.
- if (hasHyphen() && clampedOffset == length())
- clampedOffset += run().style().hyphenString().length();
-
- return clampedOffset;
+ return {
+ start(),
+ length(),
+ run().style().hyphenString().length()
+ };
}
enum class HyphenMode { Include, Ignore };
Modified: trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp (278544 => 278545)
--- trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp 2021-06-07 06:19:03 UTC (rev 278545)
@@ -55,6 +55,7 @@
#include "RuntimeEnabledFeatures.h"
#include "Settings.h"
#include "Text.h"
+#include "TextBoxSelectableRange.h"
#include "TextDecorationPainter.h"
#include "TextPaintStyle.h"
#include "TextPainter.h"
@@ -153,9 +154,9 @@
return root().selectionHeight();
}
-bool LegacyInlineTextBox::isSelected(unsigned startPosition, unsigned endPosition) const
+bool LegacyInlineTextBox::isSelectable(unsigned startPosition, unsigned endPosition) const
{
- return clampedOffset(startPosition) < clampedOffset(endPosition);
+ return selectableRange().intersects(startPosition, endPosition);
}
RenderObject::HighlightState LegacyInlineTextBox::selectionState()
@@ -243,10 +244,9 @@
// FIXME: Share more code with paintMarkedTextBackground().
LayoutRect LegacyInlineTextBox::localSelectionRect(unsigned startPos, unsigned endPos) const
{
- unsigned sPos = clampedOffset(startPos);
- unsigned ePos = clampedOffset(endPos);
+ auto [clampedStart, clampedEnd] = selectableRange().clamp(startPos, endPos);
- if (sPos >= ePos && !(startPos == endPos && startPos >= start() && startPos <= (start() + len())))
+ if (clampedStart >= clampedEnd && !(startPos == endPos && startPos >= start() && startPos <= (start() + len())))
return { };
LayoutUnit selectionTop = this->selectionTop();
@@ -256,8 +256,8 @@
LayoutRect selectionRect { LayoutUnit(logicalLeft()), selectionTop, LayoutUnit(logicalWidth()), selectionHeight };
// Avoid measuring the text when the entire line box is selected as an optimization.
- if (sPos || ePos != textRun.length())
- lineFont().adjustSelectionRectForText(textRun, selectionRect, sPos, ePos);
+ if (clampedStart || clampedEnd != textRun.length())
+ lineFont().adjustSelectionRectForText(textRun, selectionRect, clampedStart, clampedEnd);
// FIXME: The computation of the snapped selection rect differs from the computation of this rect
// in paintMarkedTextBackground(). See <https://bugs.webkit.org/show_bug.cgi?id=138913>.
return snappedSelectionRect(selectionRect, logicalRight(), selectionTop, selectionHeight, isHorizontal());
@@ -553,7 +553,8 @@
Vector<MarkedText> markedTexts;
if (paintInfo.phase != PaintPhase::Selection) {
// The marked texts for the gaps between document markers and selection are implicitly created by subdividing the entire line.
- markedTexts.append({ clampedOffset(m_start), clampedOffset(end()), MarkedText::Unmarked });
+ auto selectableRange = this->selectableRange();
+ markedTexts.append({ selectableRange.clamp(m_start), selectableRange.clamp(end()), MarkedText::Unmarked });
if (!isPrinting) {
markedTexts.appendVector(collectMarkedTextsForDocumentMarkers(TextPaintPhase::Foreground));
auto highlightMarkedTexts = collectMarkedTextsForHighlights(TextPaintPhase::Foreground);
@@ -640,35 +641,45 @@
context.concatCTM(rotation(boxRect, Counterclockwise));
}
-unsigned LegacyInlineTextBox::clampedOffset(unsigned x) const
+TextBoxSelectableRange LegacyInlineTextBox::selectableRange() const
{
- unsigned offset = std::max(std::min(x, m_start + m_len), m_start) - m_start;
- if (m_truncation == cFullTruncation)
- return offset;
- if (m_truncation != cNoTruncation)
- offset = std::min<unsigned>(offset, m_truncation);
- else if (offset == m_len) {
- // Fix up the offset if we are combined text or have a hyphen because we manage these embellishments.
- // That is, they are not reflected in renderer().text(). We treat combined text as a single unit.
- // We also treat the last codepoint in this box and the hyphen as a single unit.
+ // Fix up the offset if we are combined text or have a hyphen because we manage these embellishments.
+ // That is, they are not reflected in renderer().text(). We treat combined text as a single unit.
+ // We also treat the last codepoint in this box and the hyphen as a single unit.
+ auto additionalLengthAtEnd = [&] {
if (auto* combinedText = this->combinedText())
- offset = combinedText->combinedStringForRendering().length();
- else if (hasHyphen())
- offset += lineStyle().hyphenString().length();
- }
- return offset;
+ return combinedText->combinedStringForRendering().length() - m_len;
+ if (hasHyphen())
+ return lineStyle().hyphenString().length();
+ return 0u;
+ }();
+
+ auto truncation = [&]() -> std::optional<unsigned> {
+ if (m_truncation == cNoTruncation)
+ return { };
+ if (m_truncation == cFullTruncation)
+ return std::numeric_limits<unsigned>::max();
+ return m_truncation;
+ }();
+
+ return {
+ m_start,
+ m_len,
+ additionalLengthAtEnd,
+ truncation
+ };
}
std::pair<unsigned, unsigned> LegacyInlineTextBox::clampedStartEndForState(unsigned start, unsigned end, RenderObject::HighlightState selectionState) const
{
if (selectionState == RenderObject::HighlightState::Inside)
- return { 0, clampedOffset(m_start + m_len) };
+ return { 0, selectableRange().clamp(m_start + m_len) };
if (selectionState == RenderObject::HighlightState::Start)
end = renderer().text().length();
else if (selectionState == RenderObject::HighlightState::End)
start = 0;
- return { clampedOffset(start), clampedOffset(end) };
+ return selectableRange().clamp(start, end);
}
std::pair<unsigned, unsigned> LegacyInlineTextBox::selectionStartEnd() const
@@ -719,7 +730,7 @@
auto height = 0.13247 * fontSize;
// Avoid measuring the text when the entire line box is selected as an optimization.
- if (markedText.startOffset || markedText.endOffset != clampedOffset(end())) {
+ if (markedText.startOffset || markedText.endOffset != selectableRange().clamp(end())) {
TextRun run = createTextRun();
LayoutRect selectionRect = LayoutRect(0, y, 0, height);
lineFont().adjustSelectionRectForText(run, selectionRect, markedText.startOffset, markedText.endOffset);
@@ -770,8 +781,10 @@
{
using DraggendContentRange = std::pair<unsigned, unsigned>;
auto draggedContentRanges = renderer().draggedContentRangesBetweenOffsets(m_start, m_start + m_len);
+
Vector<MarkedText> result = draggedContentRanges.map([this] (const DraggendContentRange& range) -> MarkedText {
- return { clampedOffset(range.first), clampedOffset(range.second), MarkedText::DraggedContent };
+ auto [clampedStart, clampedEnd] = selectableRange().clamp(range.first, range.second);
+ return { clampedStart, clampedEnd, MarkedText::DraggedContent };
});
return result;
}
@@ -865,9 +878,11 @@
// FIXME: See <rdar://problem/8933352>. Also, remove the PLATFORM(IOS_FAMILY)-guard.
case DocumentMarker::DictationPhraseWithAlternatives:
#endif
- case DocumentMarker::TextMatch:
- markedTexts.uncheckedAppend({ clampedOffset(marker->startOffset()), clampedOffset(marker->endOffset()), markedTextTypeForMarkerType(marker->type()), marker });
+ case DocumentMarker::TextMatch: {
+ auto [clampedStart, clampedEnd] = selectableRange().clamp(marker->startOffset(), marker->endOffset());
+ markedTexts.uncheckedAppend({ clampedStart, clampedEnd, markedTextTypeForMarkerType(marker->type()), marker });
break;
+ }
case DocumentMarker::Replacement:
break;
#if ENABLE(TELEPHONE_NUMBER_DETECTION)
@@ -1101,8 +1116,10 @@
void LegacyInlineTextBox::paintCompositionBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin)
{
+ auto selectableRange = this->selectableRange();
+
if (!renderer().frame().editor().compositionUsesCustomHighlights()) {
- paintMarkedTextBackground(paintInfo, boxOrigin, CompositionHighlight::defaultCompositionFillColor, clampedOffset(renderer().frame().editor().compositionStart()), clampedOffset(renderer().frame().editor().compositionEnd()));
+ paintMarkedTextBackground(paintInfo, boxOrigin, CompositionHighlight::defaultCompositionFillColor, selectableRange.clamp(renderer().frame().editor().compositionStart()), selectableRange.clamp(renderer().frame().editor().compositionEnd()));
return;
}
@@ -1113,7 +1130,8 @@
if (highlight.startOffset >= end())
break;
- paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedOffset(highlight.startOffset), clampedOffset(highlight.endOffset), MarkedTextBackgroundStyle::Rounded);
+ auto [clampedStart, clampedEnd] = selectableRange.clamp(highlight.startOffset, highlight.endOffset);
+ paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedStart, clampedEnd, MarkedTextBackgroundStyle::Rounded);
if (highlight.endOffset > end())
break;
@@ -1243,9 +1261,9 @@
unsigned endOffset;
if (isLeftToRightDirection()) {
startOffset = 0;
- endOffset = clampedOffset(offset);
+ endOffset = selectableRange().clamp(offset);
} else {
- startOffset = clampedOffset(offset);
+ startOffset = selectableRange().clamp(offset);
endOffset = m_len;
}
Modified: trunk/Source/WebCore/rendering/LegacyInlineTextBox.h (278544 => 278545)
--- trunk/Source/WebCore/rendering/LegacyInlineTextBox.h 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/rendering/LegacyInlineTextBox.h 2021-06-07 06:19:03 UTC (rev 278545)
@@ -34,6 +34,7 @@
struct CompositionUnderline;
struct MarkedText;
struct StyledMarkedText;
+struct TextBoxSelectableRange;
struct TextPaintStyle;
const unsigned short cNoTruncation = USHRT_MAX;
@@ -77,6 +78,8 @@
unsigned short truncation() const { return m_truncation; }
+ TextBoxSelectableRange selectableRange() const;
+
void markDirty(bool dirty = true) final;
using LegacyInlineBox::hasHyphen;
@@ -118,7 +121,7 @@
public:
virtual LayoutRect localSelectionRect(unsigned startPos, unsigned endPos) const;
- bool isSelected(unsigned startPosition, unsigned endPosition) const;
+ bool isSelectable(unsigned startPosition, unsigned endPosition) const;
std::pair<unsigned, unsigned> selectionStartEnd() const;
std::pair<unsigned, unsigned> highlightStartEnd(HighlightData&) const;
@@ -126,8 +129,6 @@
void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override;
bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction) override;
- unsigned clampedOffset(unsigned) const;
-
private:
void deleteLine() final;
void extractLine() final;
Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.cpp (278544 => 278545)
--- trunk/Source/WebCore/rendering/RenderBlockFlow.cpp 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.cpp 2021-06-07 06:19:03 UTC (rev 278545)
@@ -3259,7 +3259,7 @@
case RenderObject::HighlightState::Both:
break;
}
- if (textBox.isSelected(start, end))
+ if (textBox.isSelectable(start, end))
return true;
}
return false;
Added: trunk/Source/WebCore/rendering/TextBoxSelectableRange.h (0 => 278545)
--- trunk/Source/WebCore/rendering/TextBoxSelectableRange.h (rev 0)
+++ trunk/Source/WebCore/rendering/TextBoxSelectableRange.h 2021-06-07 06:19:03 UTC (rev 278545)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <optional>
+
+namespace WebCore {
+
+struct TextBoxSelectableRange {
+ const unsigned start;
+ const unsigned length;
+ const unsigned additionalLengthAtEnd { 0 };
+ const std::optional<unsigned> truncation { };
+
+ unsigned clamp(unsigned offset) const
+ {
+ auto clampedOffset = std::clamp(offset, start, start + length) - start;
+
+ if (truncation)
+ return std::min<unsigned>(clampedOffset, *truncation);
+
+ if (clampedOffset == length)
+ clampedOffset += additionalLengthAtEnd;
+
+ return clampedOffset;
+ }
+
+ std::pair<unsigned, unsigned> clamp(unsigned startOffset, unsigned endOffset) const
+ {
+ return { clamp(startOffset), clamp(endOffset) };
+ }
+
+ bool intersects(unsigned startOffset, unsigned endOffset) const
+ {
+ return clamp(startOffset) < clamp(endOffset);
+ }
+};
+
+}
Modified: trunk/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp (278544 => 278545)
--- trunk/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp 2021-06-07 06:16:22 UTC (rev 278544)
+++ trunk/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp 2021-06-07 06:19:03 UTC (rev 278545)
@@ -35,6 +35,7 @@
#include "SVGRenderingContext.h"
#include "SVGResourcesCache.h"
#include "SVGRootInlineBox.h"
+#include "TextBoxSelectableRange.h"
#include "TextPainter.h"
#include <wtf/IsoMallocInlines.h>
@@ -134,11 +135,11 @@
return snappedSelectionRect;
}
-LayoutRect SVGInlineTextBox::localSelectionRect(unsigned startPosition, unsigned endPosition) const
+LayoutRect SVGInlineTextBox::localSelectionRect(unsigned start, unsigned end) const
{
- startPosition = clampedOffset(startPosition);
- endPosition = clampedOffset(endPosition);
- if (startPosition >= endPosition)
+ auto [clampedStart, clampedEnd] = selectableRange().clamp(start, end);
+
+ if (clampedStart >= clampedEnd)
return LayoutRect();
auto& style = renderer().style();
@@ -152,8 +153,8 @@
for (unsigned i = 0; i < textFragmentsSize; ++i) {
const SVGTextFragment& fragment = m_textFragments.at(i);
- fragmentStartPosition = startPosition;
- fragmentEndPosition = endPosition;
+ fragmentStartPosition = clampedStart;
+ fragmentEndPosition = clampedEnd;
if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
continue;