Skip to content

Commit

Permalink
Classify BreakLines.h
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=273729
rdar://127532669

Reviewed by Alan Baradlay.

Organize BreakLines.h functions and data into classes to namespace them
and to mark non-public items as private.

* Source/WebCore/layout/formattingContexts/inline/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::findNextBreakablePosition):
* Source/WebCore/rendering/BreakLines.cpp:
(WebCore:::m_table):
* Source/WebCore/rendering/BreakLines.h:
(WebCore::BreakLines::nextBreakablePosition):
(WebCore::BreakLines::LineBreakTable::unsafeLookup const):
(WebCore::BreakLines::isBreakableSpace):
(WebCore::BreakLines::nextBreakableSpace):
(WebCore::BreakLines::nextCharacter):
(WebCore::BreakLines::isBreakable):
(WebCore::nextBreakablePosition): Deleted.
(WebCore::lineBreakTableUnsafeLookup): Deleted.
(WebCore::isBreakableSpace): Deleted.
(WebCore::nextBreakableSpace): Deleted.
(WebCore::nextCharacter): Deleted.
(WebCore::isBreakable): Deleted.
* Source/WebCore/rendering/RenderText.cpp:
(WebCore::RenderText::computePreferredLogicalWidths):
* Source/WebCore/rendering/line/BreakingContext.h:
(WebCore::BreakingContext::handleText):
* Source/WebKitLegacy/ios/Misc/WebUIKitSupport.mm:
(WebKitGetLastLineBreakInBuffer):

Canonical link: https://commits.webkit.org/278626@main
  • Loading branch information
fantasai committed May 10, 2024
1 parent 3dc8b21 commit fffbee3
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -365,19 +365,19 @@ unsigned TextUtil::findNextBreakablePosition(CachedLineBreakIteratorFactory& lin

if (keepAllWordsForCJK) {
if (breakNBSP)
return nextBreakablePosition<LineBreakRules::Special, WordBreakBehavior::KeepAll, NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return nextBreakablePosition<LineBreakRules::Special, WordBreakBehavior::KeepAll, NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Special, BreakLines::WordBreakBehavior::KeepAll, BreakLines::NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Special, BreakLines::WordBreakBehavior::KeepAll, BreakLines::NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
}

if (lineBreakIteratorFactory.mode() == TextBreakIterator::LineMode::Behavior::Default) {
if (breakNBSP)
return nextBreakablePosition<LineBreakRules::Normal, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return nextBreakablePosition<LineBreakRules::Normal, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Normal, BreakLines::WordBreakBehavior::Normal, BreakLines::NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Normal, BreakLines::WordBreakBehavior::Normal, BreakLines::NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
}

if (breakNBSP)
return nextBreakablePosition<LineBreakRules::Special, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return nextBreakablePosition<LineBreakRules::Special, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Special, BreakLines::WordBreakBehavior::Normal, BreakLines::NoBreakSpaceBehavior::Break>(lineBreakIteratorFactory, startPosition);
return BreakLines::nextBreakablePosition<BreakLines::LineBreakRules::Special, BreakLines::WordBreakBehavior::Normal, BreakLines::NoBreakSpaceBehavior::Normal>(lineBreakIteratorFactory, startPosition);
}

bool TextUtil::shouldPreserveSpacesAndTabs(const Box& layoutBox)
Expand Down
4 changes: 1 addition & 3 deletions Source/WebCore/rendering/BreakLines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace WebCore {
// - after '-' and '?' (backward-compatible, and compatible with Internet Explorer).
// Please refer to <https://bugs.webkit.org/show_bug.cgi?id=37698> for line breaking matrixes of different browsers
// and the ICU standard.
const unsigned char lineBreakTable[][lineBreakTableColumnCount] = {
const unsigned char BreakLines::LineBreakTable::breakTable[rowCount][columnCount] = {
// ! " # $ % & ' ( ) * + , - . / 0 1-8 9 : ; < = > ? @ A-X Y Z [ \ ] ^ _ ` a-x y z { | } ~ DEL
{ B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // !
{ B(0, 0, 0, 0, 0, 0, 0, 1), B(0, 0, 0, 0, 0, 0, 0, 0), 0, B(0, 0, 0, 1, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0), 0, 0, 0, B(0, 0, 1, 0, 0, 0, 0, 0) }, // "
Expand Down Expand Up @@ -95,6 +95,4 @@ const unsigned char lineBreakTable[][lineBreakTableColumnCount] = {
#undef DI
#undef AL

static_assert(std::size(lineBreakTable) == lineBreakTableLastCharacter - lineBreakTableFirstCharacter + 1, "Test LineBreakTable consistency");

} // namespace WebCore
112 changes: 66 additions & 46 deletions Source/WebCore/rendering/BreakLines.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,65 @@

namespace WebCore {

enum class NoBreakSpaceBehavior {
Normal,
Break,
};

enum class WordBreakBehavior {
Normal,
BreakAll,
KeepAll,
};
class BreakLines {
public:
enum class NoBreakSpaceBehavior {
Normal,
Break,
};
enum class WordBreakBehavior {
Normal,
BreakAll,
KeepAll,
};
enum class LineBreakRules {
Normal, // Fast path available when using default line-breaking rules within ASCII.
Special, // Uses ICU to handle special line-breaking rules.
};

template<LineBreakRules rules, WordBreakBehavior words, NoBreakSpaceBehavior spaces>
static inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory&, size_t startPosition);
static inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory& iterator, size_t startPosition)
{
return nextBreakablePosition<LineBreakRules::Normal, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Normal>(iterator, startPosition);
}
static inline bool isBreakable(CachedLineBreakIteratorFactory&, unsigned startPosition, std::optional<unsigned>& nextBreakable, bool breakNBSP, bool canUseShortcut, bool keepAllWords, bool breakAnywhere);

private:

// Helper functions.
template<NoBreakSpaceBehavior nonBreakingSpaceBehavior>
static inline bool isBreakableSpace(UChar character);

// Iterator implementations.
template<typename CharacterType, LineBreakRules shortcutRules, NoBreakSpaceBehavior nonBreakingSpaceBehavior>
static inline size_t nextBreakablePosition(CachedLineBreakIteratorFactory&, std::span<const CharacterType> string, size_t startPosition);
template<typename CharacterType, NoBreakSpaceBehavior nonBreakingSpaceBehavior>
static inline size_t nextBreakableSpace(std::span<const CharacterType> string, size_t startPosition);
static inline unsigned nextCharacter(CachedLineBreakIteratorFactory&, unsigned startPosition);

class LineBreakTable {
public:
static constexpr UChar firstCharacter = '!';
static constexpr UChar lastCharacter = 127;
static inline bool unsafeLookup(UChar before, UChar after) // Must range check before calling.
{
const unsigned beforeIndex = before - firstCharacter;
const unsigned afterIndex = after - firstCharacter;
return breakTable[beforeIndex][afterIndex / 8] & (1 << (afterIndex % 8));
}
private:
static constexpr unsigned rowCount = lastCharacter - firstCharacter + 1;
static constexpr unsigned columnCount = (lastCharacter - firstCharacter) / 8 + 1;
WEBCORE_EXPORT static const unsigned char breakTable[rowCount][columnCount];
};

enum class LineBreakRules {
Normal, // Fast path available when using default line-breaking rules within ASCII.
Special, // Uses ICU to handle special line-breaking rules.
static const LineBreakTable lineBreakTable;
};

template<LineBreakRules rules, WordBreakBehavior words, NoBreakSpaceBehavior spaces>
inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory&, size_t startPosition);
inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory& iterator, size_t startPosition)
{
return nextBreakablePosition<LineBreakRules::Normal, WordBreakBehavior::Normal, NoBreakSpaceBehavior::Normal>(iterator, startPosition);
}
inline bool isBreakable(CachedLineBreakIteratorFactory&, unsigned startPosition, std::optional<unsigned>& nextBreakable, bool breakNBSP, bool canUseShortcut, bool keepAllWords, bool breakAnywhere);

// Private Use Below

static const UChar lineBreakTableFirstCharacter = '!';
static const UChar lineBreakTableLastCharacter = 127;
static const unsigned lineBreakTableColumnCount = (lineBreakTableLastCharacter - lineBreakTableFirstCharacter) / 8 + 1;
WEBCORE_EXPORT extern const unsigned char lineBreakTable[][lineBreakTableColumnCount];
inline bool lineBreakTableUnsafeLookup(UChar before, UChar after) // Must range check before calling.
{
const unsigned beforeIndex = before - lineBreakTableFirstCharacter;
const unsigned nextIndex = after - lineBreakTableFirstCharacter;
return lineBreakTable[beforeIndex][nextIndex / 8] & (1 << (nextIndex % 8));
}

template<NoBreakSpaceBehavior nonBreakingSpaceBehavior>
static inline bool isBreakableSpace(UChar character)
template<BreakLines::NoBreakSpaceBehavior nonBreakingSpaceBehavior>
inline bool BreakLines::isBreakableSpace(UChar character)
{
switch (character) {
case ' ':
Expand All @@ -81,8 +101,8 @@ static inline bool isBreakableSpace(UChar character)
}
}

template<typename CharacterType, LineBreakRules shortcutRules, NoBreakSpaceBehavior nonBreakingSpaceBehavior>
inline size_t nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, std::span<const CharacterType> string, size_t startPosition)
template<typename CharacterType, BreakLines::LineBreakRules shortcutRules, BreakLines::NoBreakSpaceBehavior nonBreakingSpaceBehavior>
inline size_t BreakLines::nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, std::span<const CharacterType> string, size_t startPosition)
{
CharacterType beforeBefore = startPosition > 1 ? string[startPosition - 2]
: static_cast<CharacterType>(lineBreakIteratorFactory.priorContext().secondToLastCharacter());
Expand Down Expand Up @@ -112,9 +132,9 @@ inline size_t nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIte

// If both characters are ASCII, use a lookup table for enhanced speed
// and for compatibility with other browsers (see comments on lineBreakTable for details).
if (before <= lineBreakTableLastCharacter && after <= lineBreakTableLastCharacter) {
if (before >= lineBreakTableFirstCharacter && after >= lineBreakTableFirstCharacter) {
if (lineBreakTableUnsafeLookup(before, after))
if (before <= lineBreakTable.lastCharacter && after <= lineBreakTable.lastCharacter) {
if (before >= lineBreakTable.firstCharacter && after >= lineBreakTable.firstCharacter) {
if (lineBreakTable.unsafeLookup(before, after))
return i;
} // Else at least one is an ASCII control character; don't break.
continue;
Expand All @@ -140,8 +160,8 @@ inline size_t nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIte
return string.size();
}

template<typename CharacterType, NoBreakSpaceBehavior nonBreakingSpaceBehavior>
inline size_t nextBreakableSpace(std::span<const CharacterType> string, size_t startPosition)
template<typename CharacterType, BreakLines::NoBreakSpaceBehavior nonBreakingSpaceBehavior>
inline size_t BreakLines::nextBreakableSpace(std::span<const CharacterType> string, size_t startPosition)
{
// FIXME: Use ICU instead.
for (size_t i = startPosition; i < string.size(); ++i) {
Expand All @@ -156,7 +176,7 @@ inline size_t nextBreakableSpace(std::span<const CharacterType> string, size_t s
return string.size();
}

inline unsigned nextCharacter(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, unsigned startPosition)
inline unsigned BreakLines::nextCharacter(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, unsigned startPosition)
{
auto stringView = lineBreakIteratorFactory.stringView();
ASSERT(startPosition <= stringView.length());
Expand All @@ -167,8 +187,8 @@ inline unsigned nextCharacter(CachedLineBreakIteratorFactory& lineBreakIteratorF
return next.value_or(stringView.length());
}

template<LineBreakRules rules, WordBreakBehavior words, NoBreakSpaceBehavior spaces>
inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, size_t startPosition)
template<BreakLines::LineBreakRules rules, BreakLines::WordBreakBehavior words, BreakLines::NoBreakSpaceBehavior spaces>
inline unsigned BreakLines::nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, size_t startPosition)
{
auto stringView = lineBreakIteratorFactory.stringView();
if (stringView.is8Bit()) {
Expand All @@ -182,7 +202,7 @@ inline unsigned nextBreakablePosition(CachedLineBreakIteratorFactory& lineBreakI
}


inline bool isBreakable(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, unsigned startPosition, std::optional<unsigned>& nextBreakable, bool breakNBSP, bool canUseShortcut, bool keepAllWords, bool breakAnywhere)
inline bool BreakLines::isBreakable(CachedLineBreakIteratorFactory& lineBreakIteratorFactory, unsigned startPosition, std::optional<unsigned>& nextBreakable, bool breakNBSP, bool canUseShortcut, bool keepAllWords, bool breakAnywhere)
{
if (nextBreakable && nextBreakable.value() >= startPosition)
return startPosition == nextBreakable;
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/rendering/RenderText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, SingleThreadWeak
continue;
}

bool hasBreak = breakAll || isBreakable(lineBreakIteratorFactory, i, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere);
bool hasBreak = breakAll || BreakLines::isBreakable(lineBreakIteratorFactory, i, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere);
bool betweenWords = true;
unsigned j = i;
while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && c != zeroWidthSpace && (c != softHyphen || style.hyphens() == Hyphens::None)) {
Expand All @@ -1275,7 +1275,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, SingleThreadWeak
c = string[j];
if (U_IS_LEAD(previousCharacter) && U_IS_TRAIL(c))
continue;
if (isBreakable(lineBreakIteratorFactory, j, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere) && characterAt(j - 1) != softHyphen)
if (BreakLines::isBreakable(lineBreakIteratorFactory, j, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere) && characterAt(j - 1) != softHyphen)
break;
if (breakAll) {
// FIXME: This code is ultra wrong.
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/rendering/line/BreakingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ inline bool BreakingContext::handleText()

std::optional<unsigned> nextBreakablePosition = m_current.nextBreakablePosition();
auto mayBreakHere = !(m_currentWhitespaceCollapse == WhiteSpaceCollapse::Preserve && m_currentTextWrap == TextWrapMode::NoWrap);
bool betweenWords = c == newlineCharacter || (mayBreakHere && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIteratorFactory, m_current.offset(), nextBreakablePosition, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere));
bool betweenWords = c == newlineCharacter || (mayBreakHere && !m_atStart && BreakLines::isBreakable(m_renderTextInfo.lineBreakIteratorFactory, m_current.offset(), nextBreakablePosition, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere));
m_current.setNextBreakablePosition(nextBreakablePosition);

if (canHangStopOrCommaAtLineEnd && renderer.isHangableStopOrComma(c) && m_width.fitsOnLine()) {
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKitLegacy/ios/Misc/WebUIKitSupport.mm
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ int WebKitGetLastLineBreakInBuffer(UChar *characters, int position, int length)
unsigned lastBreakPos = position;
unsigned breakPos = 0;
CachedLineBreakIteratorFactory lineBreakIteratorFactory(StringView { std::span(characters, length) });
while (static_cast<int>(breakPos = nextBreakablePosition(lineBreakIteratorFactory, breakPos)) < position)
while (static_cast<int>(breakPos = BreakLines::nextBreakablePosition(lineBreakIteratorFactory, breakPos)) < position)
lastBreakPos = breakPos++;
return static_cast<int>(lastBreakPos) < position ? lastBreakPos : INT_MAX;
}
Expand Down

0 comments on commit fffbee3

Please sign in to comment.