| 86 | }; |
| 87 | |
| 88 | static LineBreakResult lineBreak(const ShapedGlyph* begin, |
| 89 | const ShapedGlyph* end, |
| 90 | LineBreakStrategy strategy, |
| 91 | Scalar containerWidth, |
| 92 | Scalar accumulatedWidth) { |
| 93 | const auto* it = begin; |
| 94 | // The last iterator that we can safely break on |
| 95 | const auto* lastSafeBreakIt = it; |
| 96 | auto prevWasWhitespace = false; |
| 97 | |
| 98 | while (it < end) { |
| 99 | if (Unicode::isNewline(it->character())) { |
| 100 | return LineBreakResult(it, it + 1, true, true); |
| 101 | } |
| 102 | |
| 103 | accumulatedWidth += it->advanceX; |
| 104 | |
| 105 | auto isWhitespace = Unicode::isBreakingWhitespace(it->character()); |
| 106 | |
| 107 | switch (strategy) { |
| 108 | case LineBreakStrategy::ByWord: |
| 109 | if (isWhitespace && !prevWasWhitespace) { |
| 110 | lastSafeBreakIt = it; |
| 111 | } |
| 112 | break; |
| 113 | case LineBreakStrategy::ByCharacter: |
| 114 | if (!it->unsafeToBreak() && !prevWasWhitespace) { |
| 115 | lastSafeBreakIt = it; |
| 116 | } |
| 117 | break; |
| 118 | } |
| 119 | |
| 120 | if (accumulatedWidth > containerWidth) { |
| 121 | // Reached the end of our container |
| 122 | |
| 123 | if (!isWhitespace) { |
| 124 | // If we are not in a whitespace, we move back the iterator |
| 125 | // down to our first safe breaking point in order to consume |
| 126 | // all the breaking whitespaces that might be there. |
| 127 | // This is to set our next iterator on the first word instead |
| 128 | // of having leading whitespaces. |
| 129 | it = lastSafeBreakIt; |
| 130 | } |
| 131 | |
| 132 | // Eat up all the trailing whitespaces |
| 133 | while (it < end && Unicode::isBreakingWhitespace(it->character())) { |
| 134 | it++; |
| 135 | } |
| 136 | |
| 137 | return LineBreakResult(lastSafeBreakIt, it, true, false); |
| 138 | } |
| 139 | |
| 140 | prevWasWhitespace = isWhitespace; |
| 141 | it++; |
| 142 | } |
| 143 | |
| 144 | return LineBreakResult(it, it, false, false); |
| 145 | } |
no test coverage detected