* Shape a single run. * * @param buff The buffer of which a partial (depending on start/length of the run) will be shaped. * @param length The length of the buffer. */
| 148 | * @param length The length of the buffer. |
| 149 | */ |
| 150 | void ICURun::Shape(UChar *buff, size_t buff_length) |
| 151 | { |
| 152 | auto hbfont = hb_ft_font_create_referenced(*(static_cast<const FT_Face *>(font->fc->GetOSHandle()))); |
| 153 | /* Match the flags with how we render the glyphs. */ |
| 154 | hb_ft_font_set_load_flags(hbfont, GetFontAAState() ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO); |
| 155 | |
| 156 | /* ICU buffer is in UTF-16. */ |
| 157 | auto hbbuf = hb_buffer_create(); |
| 158 | hb_buffer_add_utf16(hbbuf, reinterpret_cast<uint16_t *>(buff), buff_length, this->start, this->length); |
| 159 | |
| 160 | /* Set all the properties of this segment. */ |
| 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)); |
| 163 | hb_buffer_set_language(hbbuf, hb_language_from_string(_current_language->isocode, -1)); |
| 164 | hb_buffer_set_cluster_level(hbbuf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES); |
| 165 | |
| 166 | /* Shape the segment. */ |
| 167 | hb_shape(hbfont, hbbuf, nullptr, 0); |
| 168 | |
| 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); |
| 172 | |
| 173 | /* Make sure any former run is lost. */ |
| 174 | this->glyphs.clear(); |
| 175 | this->glyph_to_char.clear(); |
| 176 | this->positions.clear(); |
| 177 | this->advance.clear(); |
| 178 | |
| 179 | /* Reserve space, as we already know the size. */ |
| 180 | this->glyphs.reserve(glyph_count); |
| 181 | this->glyph_to_char.reserve(glyph_count); |
| 182 | this->positions.reserve(glyph_count); |
| 183 | this->advance.reserve(glyph_count); |
| 184 | |
| 185 | /* Prepare the glyphs/position. ICUVisualRun will give the position an offset if needed. */ |
| 186 | hb_position_t advance = 0; |
| 187 | for (unsigned int i = 0; i < glyph_count; i++) { |
| 188 | int x_advance; |
| 189 | |
| 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]); |
| 192 | x_advance = this->font->fc->GetGlyphWidth(glyph); |
| 193 | this->glyphs.push_back(glyph); |
| 194 | this->positions.emplace_back(advance, advance + x_advance - 1, (this->font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(this->font->fc->GetSize()))) / 2); // Align sprite font to centre |
| 195 | } else { |
| 196 | x_advance = glyph_pos[i].x_advance / FONT_SCALE; |
| 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].x_offset / FONT_SCALE + advance + x_advance - 1, glyph_pos[i].y_offset / FONT_SCALE); |
| 199 | } |
| 200 | |
| 201 | this->glyph_to_char.push_back(glyph_info[i].cluster); |
| 202 | this->advance.push_back(x_advance); |
| 203 | advance += x_advance; |
| 204 | } |
| 205 | |
| 206 | /* Track the total advancement we made. */ |
| 207 | this->total_advance = advance; |
no test coverage detected