Determine the glyph positions for a run. */
| 154 | |
| 155 | /** Determine the glyph positions for a run. */ |
| 156 | static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *buff, UniscribeRun &range) |
| 157 | { |
| 158 | /* Initial size guess for the number of glyphs recommended by Uniscribe. */ |
| 159 | range.glyphs.resize(range.len * 3 / 2 + 16); |
| 160 | range.vis_attribs.resize(range.glyphs.size()); |
| 161 | |
| 162 | /* The char-to-glyph array is the same size as the input. */ |
| 163 | range.char_to_glyph.resize(range.len); |
| 164 | |
| 165 | HDC temp_dc = nullptr; |
| 166 | HFONT old_font = nullptr; |
| 167 | HFONT cur_font = nullptr; |
| 168 | |
| 169 | while (true) { |
| 170 | /* Shape the text run by determining the glyphs needed for display. */ |
| 171 | int glyphs_used = 0; |
| 172 | HRESULT hr = ScriptShape(temp_dc, &_script_cache[range.font->fc->GetSize()], buff + range.pos, range.len, (int)range.glyphs.size(), &range.sa, &range.glyphs[0], &range.char_to_glyph[0], &range.vis_attribs[0], &glyphs_used); |
| 173 | |
| 174 | if (SUCCEEDED(hr)) { |
| 175 | range.glyphs.resize(glyphs_used); |
| 176 | range.vis_attribs.resize(glyphs_used); |
| 177 | |
| 178 | /* Calculate the glyph positions. */ |
| 179 | ABC abc; |
| 180 | range.advances.resize(range.glyphs.size()); |
| 181 | range.offsets.resize(range.glyphs.size()); |
| 182 | hr = ScriptPlace(temp_dc, &_script_cache[range.font->fc->GetSize()], &range.glyphs[0], (int)range.glyphs.size(), &range.vis_attribs[0], &range.sa, &range.advances[0], &range.offsets[0], &abc); |
| 183 | if (SUCCEEDED(hr)) { |
| 184 | /* We map our special sprite chars to values that don't fit into a WORD. Copy the glyphs |
| 185 | * into a new vector and query the real glyph to use for these special chars. */ |
| 186 | range.ft_glyphs.resize(range.glyphs.size()); |
| 187 | for (size_t g_id = 0; g_id < range.glyphs.size(); g_id++) { |
| 188 | range.ft_glyphs[g_id] = range.glyphs[g_id]; |
| 189 | } |
| 190 | for (int i = 0; i < range.len; i++) { |
| 191 | if (buff[range.pos + i] >= SCC_SPRITE_START && buff[range.pos + i] <= SCC_SPRITE_END) { |
| 192 | auto pos = range.char_to_glyph[i]; |
| 193 | if (range.ft_glyphs[pos] == 0) { // Font doesn't have our special glyph, so remap. |
| 194 | range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); |
| 195 | range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre |
| 196 | range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | range.total_advance = 0; |
| 202 | for (size_t i = 0; i < range.advances.size(); i++) { |
| 203 | #ifdef WITH_FREETYPE |
| 204 | /* FreeType and GDI/Uniscribe seems to occasionally disagree over the width of a glyph. */ |
| 205 | if (range.advances[i] > 0 && range.ft_glyphs[i] != 0xFFFF) range.advances[i] = range.font->fc->GetGlyphWidth(range.ft_glyphs[i]); |
| 206 | #endif |
| 207 | range.total_advance += range.advances[i]; |
| 208 | } |
| 209 | break; |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | if (hr == E_OUTOFMEMORY) { |
no test coverage detected