19 #include "3rdparty/icu/scriptrun.h"
21 #include <unicode/ubidi.h>
22 #include <unicode/brkiter.h>
64 std::vector<GlyphID> glyphs;
65 std::vector<Point> positions;
66 std::vector<int> glyph_to_char;
74 const std::vector<GlyphID> &GetGlyphs()
const override {
return this->glyphs; }
75 const std::vector<Point> &GetPositions()
const override {
return this->positions; }
76 const std::vector<int> &GetGlyphToCharMap()
const override {
return this->glyph_to_char; }
78 const Font *GetFont()
const override {
return this->font; }
79 int GetLeading()
const override {
return this->font->
fc->
GetHeight(); }
80 int GetGlyphCount()
const override {
return this->glyphs.size(); }
81 int GetAdvance()
const {
return this->total_advance; }
89 int CountRuns()
const override {
return (uint)this->size(); }
90 const VisualRun &GetVisualRun(
int run)
const override {
return this->at(run); }
92 int GetInternalCharLength(char32_t c)
const override
95 return c >= 0x010000U ? 2 : 1;
100 std::vector<ICURun> runs;
103 std::vector<ICURun>::iterator current_run;
107 ICUParagraphLayout(std::vector<ICURun> &runs, UChar *buff,
size_t buff_length) : runs(runs), buff(buff), buff_length(buff_length)
114 void Reflow()
override
116 this->current_run = this->runs.begin();
117 this->partial_offset = 0;
120 std::unique_ptr<const Line> NextLine(
int max_width)
override;
132 glyphs(run.glyphs), glyph_to_char(run.glyph_to_char), total_advance(run.total_advance), font(run.font)
136 this->positions.reserve(run.
positions.size());
140 this->positions.emplace_back(pt.x + x, pt.y);
152 auto hbfont = hb_ft_font_create_referenced(*(
static_cast<const FT_Face *
>(font->fc->GetOSHandle())));
154 hb_ft_font_set_load_flags(hbfont, GetFontAAState(this->font->fc->GetSize()) ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
157 auto hbbuf = hb_buffer_create();
158 hb_buffer_add_utf16(hbbuf,
reinterpret_cast<uint16_t *
>(buff), buff_length, this->start, this->length);
161 hb_buffer_set_direction(hbbuf, (this->level & 1) == 1 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
162 hb_buffer_set_script(hbbuf, hb_script_from_string(uscript_getShortName(this->script), -1));
164 hb_buffer_set_cluster_level(hbbuf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
167 hb_shape(hbfont, hbbuf,
nullptr, 0);
169 unsigned int glyph_count;
170 auto glyph_info = hb_buffer_get_glyph_infos(hbbuf, &glyph_count);
171 auto glyph_pos = hb_buffer_get_glyph_positions(hbbuf, &glyph_count);
174 this->glyphs.clear();
175 this->glyph_to_char.clear();
176 this->positions.clear();
177 this->advance.clear();
180 this->glyphs.reserve(glyph_count);
181 this->glyph_to_char.reserve(glyph_count);
182 this->positions.reserve(glyph_count + 1);
183 this->advance.reserve(glyph_count);
186 hb_position_t advance = 0;
187 for (
unsigned int i = 0; i < glyph_count; i++) {
190 if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END && glyph_info[i].codepoint == 0) {
191 auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]);
193 this->glyphs.push_back(glyph);
194 this->positions.emplace_back(advance, (this->font->fc->GetHeight() -
ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2);
195 x_advance = this->font->fc->GetGlyphWidth(glyph);
197 this->glyphs.push_back(glyph_info[i].codepoint);
198 this->positions.emplace_back(glyph_pos[i].x_offset /
FONT_SCALE + advance, glyph_pos[i].y_offset /
FONT_SCALE);
199 x_advance = glyph_pos[i].x_advance /
FONT_SCALE;
202 this->glyph_to_char.push_back(glyph_info[i].cluster);
203 this->advance.push_back(x_advance);
204 advance += x_advance;
208 this->positions.emplace_back(advance, 0);
211 this->total_advance = advance;
213 hb_buffer_destroy(hbbuf);
214 hb_font_destroy(hbfont);
224 for (
const auto &run : *
this) {
225 leading = std::max(leading, run.GetLeading());
238 for (
const auto &run : *
this) {
239 length += run.GetAdvance();
256 auto ubidi = ubidi_open();
260 UErrorCode err = U_ZERO_ERROR;
261 ubidi_setPara(ubidi, buff, length, parLevel,
nullptr, &err);
262 if (U_FAILURE(err)) {
263 Debug(fontcache, 0,
"Failed to set paragraph: %s", u_errorName(err));
265 return std::vector<ICURun>();
268 int32_t count = ubidi_countRuns(ubidi, &err);
269 if (U_FAILURE(err)) {
270 Debug(fontcache, 0,
"Failed to count runs: %s", u_errorName(err));
272 return std::vector<ICURun>();
275 std::vector<ICURun> runs;
279 int32_t logical_pos = 0;
280 while (
static_cast<size_t>(logical_pos) < length) {
281 auto start_pos = logical_pos;
285 ubidi_getLogicalRun(ubidi, start_pos, &logical_pos, &level);
287 runs.emplace_back(
ICURun(start_pos, logical_pos - start_pos, level));
290 assert(
static_cast<size_t>(count) == runs.size());
306 std::vector<ICURun>
ItemizeScript(UChar *buff,
size_t length, std::vector<ICURun> &runs_current)
308 std::vector<ICURun> runs;
309 icu::ScriptRun script_itemizer(buff, length);
312 auto cur_run = runs_current.begin();
314 while (cur_pos < script_itemizer.getScriptEnd() && cur_run != runs_current.end()) {
315 int stop_pos = std::min(script_itemizer.getScriptEnd(), cur_run->start + cur_run->length);
316 assert(stop_pos - cur_pos > 0);
318 runs.push_back(
ICURun(cur_pos, stop_pos - cur_pos, cur_run->level, script_itemizer.getScriptCode()));
320 if (stop_pos == cur_run->start + cur_run->length) cur_run++;
324 if (!script_itemizer.next())
break;
341 std::vector<ICURun> runs;
344 auto cur_run = runs_current.begin();
345 for (
auto const &font_map : font_mapping) {
346 while (cur_pos < font_map.first && cur_run != runs_current.end()) {
347 int stop_pos = std::min(font_map.first, cur_run->start + cur_run->length);
348 assert(stop_pos - cur_pos > 0);
350 runs.push_back(
ICURun(cur_pos, stop_pos - cur_pos, cur_run->level, cur_run->script, font_map.second));
352 if (stop_pos == cur_run->start + cur_run->length) cur_run++;
360 ParagraphLayouter *ICUParagraphLayoutFactory::GetParagraphLayout(UChar *buff, UChar *buff_end,
FontMap &font_mapping)
362 size_t length = buff_end - buff;
364 if (length == 0)
return nullptr;
367 for (
auto const &pair : font_mapping) {
368 if (pair.second->fc->IsBuiltInFont())
return nullptr;
375 if (runs.empty())
return nullptr;
377 for (
auto &run : runs) {
378 run.Shape(buff, length);
384 std::unique_ptr<icu::BreakIterator> ICUParagraphLayoutFactory::break_iterator;
392 UErrorCode status = U_ZERO_ERROR;
393 ICUParagraphLayoutFactory::break_iterator.reset(icu::BreakIterator::createLineInstance(locale, status));
394 assert(U_SUCCESS(status));
403 assert(ICUParagraphLayoutFactory::break_iterator !=
nullptr);
405 return std::unique_ptr<icu::BreakIterator>(ICUParagraphLayoutFactory::break_iterator->clone());
408 std::unique_ptr<const ICUParagraphLayout::Line> ICUParagraphLayout::NextLine(
int max_width)
410 std::vector<ICURun>::iterator start_run = this->current_run;
411 std::vector<ICURun>::iterator last_run = this->current_run;
413 if (start_run == this->runs.end())
return nullptr;
418 if (this->partial_offset > 0) {
419 if ((start_run->level & 1) == 0) {
420 for (
size_t i = this->partial_offset; i < start_run->advance.size(); i++) {
421 cur_width += start_run->advance[i];
424 for (
int i = 0; i < this->partial_offset; i++) {
425 cur_width += start_run->advance[i];
432 while (last_run != this->runs.end() && cur_width < max_width) {
433 cur_width += last_run->total_advance;
438 int new_partial_length = 0;
439 if (cur_width > max_width) {
442 break_iterator->setText(icu::UnicodeString(this->buff, this->buff_length));
444 auto overflow_run = last_run - 1;
448 if ((overflow_run->level & 1) == 0) {
450 for (index = overflow_run->glyphs.size(); index > 0; index--) {
451 cur_width -= overflow_run->advance[index - 1];
452 if (cur_width <= max_width)
break;
457 for (index = 0; index < overflow_run->glyphs.size(); index++) {
458 cur_width -= overflow_run->advance[index];
459 if (cur_width <= max_width)
break;
464 auto char_pos = overflow_run->glyph_to_char[index];
467 int32_t break_pos = break_iterator->preceding(char_pos + 1);
468 if (break_pos != icu::BreakIterator::DONE && break_pos > overflow_run->start + this->partial_offset) {
470 new_partial_length = break_pos - overflow_run->start - this->partial_offset;
471 }
else if (overflow_run != start_run) {
479 new_partial_length = char_pos - overflow_run->start - this->partial_offset;
484 std::vector<UBiDiLevel> bidi_level;
485 for (
auto run = start_run; run != last_run; run++) {
486 bidi_level.push_back(run->level);
488 std::vector<int32_t> vis_to_log(bidi_level.size());
489 ubidi_reorderVisual(bidi_level.data(), bidi_level.size(), vis_to_log.data());
492 std::unique_ptr<ICULine> line(
new ICULine());
495 for (
auto &i : vis_to_log) {
496 auto i_run = start_run + i;
500 if (i_run == last_run - 1 && new_partial_length > 0) {
501 if (i_run == start_run && this->partial_offset > 0) {
502 assert(run.
length > this->partial_offset);
503 run.
start += this->partial_offset;
504 run.
length -= this->partial_offset;
507 assert(run.
length > new_partial_length);
508 run.
length = new_partial_length;
510 run.
Shape(this->buff, this->buff_length);
511 }
else if (i_run == start_run && this->partial_offset > 0) {
512 assert(run.
length > this->partial_offset);
514 run.
start += this->partial_offset;
515 run.
length -= this->partial_offset;
517 run.
Shape(this->buff, this->buff_length);
521 line->emplace_back(std::move(run), cur_pos);
522 cur_pos += total_advance;
525 if (new_partial_length > 0) {
526 this->current_run = last_run - 1;
527 this->partial_offset += new_partial_length;
529 this->current_run = last_run;
530 this->partial_offset = 0;
536 size_t ICUParagraphLayoutFactory::AppendToBuffer(UChar *buff,
const UChar *buffer_last, char32_t c)
538 assert(buff < buffer_last);
541 UErrorCode err = U_ZERO_ERROR;
542 u_strFromUTF32(buff, buffer_last - buff, &length, (UChar32*)&c, 1, &err);