virtual */
| 317 | } |
| 318 | |
| 319 | /* virtual */ std::unique_ptr<const ParagraphLayouter::Line> UniscribeParagraphLayout::NextLine(int max_width) |
| 320 | { |
| 321 | std::vector<UniscribeRun>::iterator start_run = this->cur_range; |
| 322 | std::vector<UniscribeRun>::iterator last_run = this->cur_range; |
| 323 | |
| 324 | if (start_run == this->ranges.end()) return nullptr; |
| 325 | |
| 326 | /* Add remaining width of the first run if it is a broken run. */ |
| 327 | int cur_width = 0; |
| 328 | if (this->cur_range_offset != 0) { |
| 329 | std::vector<int> dx(start_run->len); |
| 330 | ScriptGetLogicalWidths(&start_run->sa, start_run->len, (int)start_run->glyphs.size(), &start_run->advances[0], &start_run->char_to_glyph[0], &start_run->vis_attribs[0], &dx[0]); |
| 331 | |
| 332 | for (std::vector<int>::const_iterator c = dx.begin() + this->cur_range_offset; c != dx.end(); c++) { |
| 333 | cur_width += *c; |
| 334 | } |
| 335 | ++last_run; |
| 336 | } |
| 337 | |
| 338 | /* Gather runs until the line is full. */ |
| 339 | while (last_run != this->ranges.end() && cur_width <= max_width) { |
| 340 | cur_width += last_run->total_advance; |
| 341 | ++last_run; |
| 342 | } |
| 343 | |
| 344 | /* If the text does not fit into the available width, find a suitable breaking point. */ |
| 345 | int remaining_offset = (last_run - 1)->len + 1; |
| 346 | int whitespace_count = 0; |
| 347 | if (cur_width > max_width) { |
| 348 | std::vector<SCRIPT_LOGATTR> log_attribs; |
| 349 | |
| 350 | /* Get word break information. */ |
| 351 | int width_avail = max_width; |
| 352 | int num_chars = this->cur_range_offset; |
| 353 | int start_offs = this->cur_range_offset; |
| 354 | int last_cluster = this->cur_range_offset + 1; |
| 355 | for (std::vector<UniscribeRun>::iterator r = start_run; r != last_run; r++) { |
| 356 | log_attribs.resize(r->pos - start_run->pos + r->len); |
| 357 | if (FAILED(ScriptBreak(this->text_buffer + r->pos + start_offs, r->len - start_offs, &r->sa, &log_attribs[r->pos - start_run->pos + start_offs]))) return nullptr; |
| 358 | |
| 359 | std::vector<int> dx(r->len); |
| 360 | ScriptGetLogicalWidths(&r->sa, r->len, (int)r->glyphs.size(), &r->advances[0], &r->char_to_glyph[0], &r->vis_attribs[0], &dx[0]); |
| 361 | |
| 362 | /* Count absolute max character count on the line. */ |
| 363 | for (int c = start_offs; c < r->len && width_avail > 0; c++, num_chars++) { |
| 364 | if (c > start_offs && log_attribs[num_chars].fCharStop) last_cluster = num_chars; |
| 365 | width_avail -= dx[c]; |
| 366 | } |
| 367 | |
| 368 | start_offs = 0; |
| 369 | } |
| 370 | |
| 371 | /* Walk backwards to find the last suitable breaking point. */ |
| 372 | while (--num_chars > this->cur_range_offset && !log_attribs[num_chars].fSoftBreak && !log_attribs[num_chars].fWhiteSpace) {} |
| 373 | |
| 374 | if (num_chars == this->cur_range_offset) { |
| 375 | /* Didn't find any suitable word break point, just break on the last cluster boundary. */ |
| 376 | num_chars = last_cluster; |