summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibGfx')
-rw-r--r--Userland/Libraries/LibGfx/TextLayout.cpp105
1 files changed, 75 insertions, 30 deletions
diff --git a/Userland/Libraries/LibGfx/TextLayout.cpp b/Userland/Libraries/LibGfx/TextLayout.cpp
index b3aafe379d..b8f9900130 100644
--- a/Userland/Libraries/LibGfx/TextLayout.cpp
+++ b/Userland/Libraries/LibGfx/TextLayout.cpp
@@ -9,8 +9,16 @@
namespace Gfx {
-// HACK: We need to point to some valid memory with Utf8Views.
-char const s_the_newline[] = "\n";
+enum class BlockType {
+ Newline,
+ Whitespace,
+ Word
+};
+
+struct Block {
+ BlockType type;
+ Utf8View characters;
+};
IntRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const
{
@@ -34,37 +42,69 @@ IntRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const
Vector<String, 32> TextLayout::wrap_lines(TextElision elision, TextWrapping wrapping, int line_spacing, FitWithinRect fit_within_rect) const
{
- Vector<Utf8View> words;
+ Vector<Block> blocks;
+
+ Optional<BlockType> current_block_type;
+ size_t block_start_offset;
- Optional<size_t> start_byte_offset;
- size_t current_byte_offset = 0;
+ size_t offset = 0;
for (auto it = m_text.begin(); !it.done(); ++it) {
- current_byte_offset = m_text.iterator_offset(it);
+ offset = m_text.iterator_offset(it);
switch (*it) {
- case '\n':
- case '\r':
case '\t':
case ' ': {
- if (start_byte_offset.has_value())
- words.append(m_text.substring_view(start_byte_offset.value(), current_byte_offset - start_byte_offset.value()));
- start_byte_offset.clear();
+ if (current_block_type.has_value() && current_block_type.value() != BlockType::Whitespace) {
+ blocks.append({
+ current_block_type.value(),
+ m_text.substring_view(block_start_offset, offset - block_start_offset),
+ });
+ current_block_type.clear();
+ }
- if (*it == '\n') {
- words.append(Utf8View { s_the_newline });
+ if (!current_block_type.has_value()) {
+ current_block_type = BlockType::Whitespace;
+ block_start_offset = offset;
}
continue;
}
+ case '\n':
+ case '\r': {
+ if (current_block_type.has_value()) {
+ blocks.append({
+ current_block_type.value(),
+ m_text.substring_view(block_start_offset, offset - block_start_offset),
+ });
+ current_block_type.clear();
+ }
+
+ blocks.append({ BlockType::Newline, Utf8View {} });
+ continue;
+ }
default: {
- if (!start_byte_offset.has_value())
- start_byte_offset = current_byte_offset;
+ if (current_block_type.has_value() && current_block_type.value() != BlockType::Word) {
+ blocks.append({
+ current_block_type.value(),
+ m_text.substring_view(block_start_offset, offset - block_start_offset),
+ });
+ current_block_type.clear();
+ }
+
+ if (!current_block_type.has_value()) {
+ current_block_type = BlockType::Word;
+ block_start_offset = offset;
+ }
}
}
}
- if (start_byte_offset.has_value())
- words.append(m_text.substring_view(start_byte_offset.value(), m_text.byte_length() - start_byte_offset.value()));
+ if (current_block_type.has_value()) {
+ blocks.append({
+ current_block_type.value(),
+ m_text.substring_view(block_start_offset, m_text.byte_length() - block_start_offset),
+ });
+ }
size_t max_lines_that_can_fit = 0;
if (m_rect.height() >= m_font->glyph_height()) {
@@ -81,46 +121,51 @@ Vector<String, 32> TextLayout::wrap_lines(TextElision elision, TextWrapping wrap
StringBuilder builder;
size_t line_width = 0;
bool did_not_finish = false;
- for (auto& word : words) {
-
- if (word.as_string() == s_the_newline) {
+ for (Block& block : blocks) {
+ switch (block.type) {
+ case BlockType::Newline: {
lines.append(builder.to_string());
builder.clear();
line_width = 0;
if (lines.size() == max_lines_that_can_fit && fit_within_rect == FitWithinRect::Yes) {
did_not_finish = true;
- break;
+ goto blocks_processed;
}
- } else {
- size_t word_width = font().width(word);
+
+ continue;
+ }
+ case BlockType::Whitespace:
+ case BlockType::Word: {
+ size_t block_width = font().width(block.characters);
if (line_width > 0) {
- word_width += font().glyph_width('x');
+ block_width += font().glyph_width('x');
- if (wrapping == TextWrapping::Wrap && line_width + word_width > static_cast<unsigned>(m_rect.width())) {
+ if (wrapping == TextWrapping::Wrap && line_width + block_width > static_cast<unsigned>(m_rect.width())) {
lines.append(builder.to_string());
builder.clear();
line_width = 0;
if (lines.size() == max_lines_that_can_fit && fit_within_rect == FitWithinRect::Yes) {
did_not_finish = true;
- break;
+ goto blocks_processed;
}
}
-
- builder.append(' ');
}
+
if (lines.size() == max_lines_that_can_fit && fit_within_rect == FitWithinRect::Yes) {
did_not_finish = true;
break;
}
- builder.append(word.as_string());
- line_width += word_width;
+ builder.append(block.characters.as_string());
+ line_width += block_width;
+ }
}
}
+blocks_processed:
if (!did_not_finish) {
auto last_line = builder.to_string();
if (!last_line.is_empty())