* Construct a new line with a maximum width. * @param max_width The maximum width of the string. * @return A Line, or nullptr when at the end of the paragraph. */
| 210 | * @return A Line, or nullptr when at the end of the paragraph. |
| 211 | */ |
| 212 | std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine(int max_width) |
| 213 | { |
| 214 | /* Simple idea: |
| 215 | * - split a line at a newline character, or at a space where we can break a line. |
| 216 | * - split for a visual run whenever a new line happens, or the font changes. |
| 217 | */ |
| 218 | if (this->buffer == nullptr) return nullptr; |
| 219 | |
| 220 | std::unique_ptr<FallbackLine> l = std::make_unique<FallbackLine>(); |
| 221 | |
| 222 | if (*this->buffer == '\0') { |
| 223 | /* Only a newline. */ |
| 224 | this->buffer = nullptr; |
| 225 | l->emplace_back(this->runs.begin()->second, this->buffer, 0, 0, 0); |
| 226 | return l; |
| 227 | } |
| 228 | |
| 229 | int offset = this->buffer - this->buffer_begin; |
| 230 | FontMap::iterator iter = this->runs.begin(); |
| 231 | while (iter->first <= offset) { |
| 232 | ++iter; |
| 233 | assert(iter != this->runs.end()); |
| 234 | } |
| 235 | |
| 236 | const FontCache *fc = iter->second->fc; |
| 237 | const char32_t *next_run = this->buffer_begin + iter->first; |
| 238 | |
| 239 | const char32_t *begin = this->buffer; |
| 240 | const char32_t *last_space = nullptr; |
| 241 | const char32_t *last_char; |
| 242 | int width = 0; |
| 243 | for (;;) { |
| 244 | char32_t c = *this->buffer; |
| 245 | last_char = this->buffer; |
| 246 | |
| 247 | if (c == '\0') { |
| 248 | this->buffer = nullptr; |
| 249 | break; |
| 250 | } |
| 251 | |
| 252 | if (this->buffer == next_run) { |
| 253 | int w = l->GetWidth(); |
| 254 | l->emplace_back(iter->second, begin, this->buffer - begin, begin - this->buffer_begin, w); |
| 255 | ++iter; |
| 256 | assert(iter != this->runs.end()); |
| 257 | |
| 258 | next_run = this->buffer_begin + iter->first; |
| 259 | begin = this->buffer; |
| 260 | /* Since a next run is started, there is already some text that |
| 261 | * will be shown for this line. However, we do not want to break |
| 262 | * this line at the previous space, so pretend we passed a space |
| 263 | * just before this next run. */ |
| 264 | last_space = begin - 1; |
| 265 | } |
| 266 | |
| 267 | if (IsWhitespace(c)) last_space = this->buffer; |
| 268 | |
| 269 | if (IsPrintable(c) && !IsTextDirectionChar(c)) { |
nothing calls this directly
no test coverage detected