Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <gcach_ftyp.hxx>
21 : #include <sallayout.hxx>
22 : #include <salgdi.hxx>
23 : #include <scrptrun.h>
24 :
25 : #include <boost/static_assert.hpp>
26 :
27 : #include <i18nlangtag/mslangid.hxx>
28 :
29 : #include <vcl/svapp.hxx>
30 : #include <vcl/unohelp.hxx>
31 :
32 : #include <sal/alloca.h>
33 : #include <rtl/instance.hxx>
34 :
35 : #include <hb-icu.h>
36 : #include <hb-ot.h>
37 :
38 : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
39 :
40 : // layout implementation for ServerFont
41 2156373 : ServerFontLayout::ServerFontLayout( ServerFont& rFont )
42 2156373 : : mrServerFont( rFont )
43 : {
44 2156373 : }
45 :
46 341169 : void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
47 : {
48 341169 : rSalGraphics.DrawServerFontLayout( *this );
49 341169 : }
50 :
51 2156373 : bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
52 : {
53 2156373 : return mrServerFont.GetLayoutEngine()->layout(*this, rArgs);
54 : }
55 :
56 2157095 : void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
57 : {
58 2157095 : GenericSalLayout::AdjustLayout( rArgs );
59 :
60 : // apply asian kerning if the glyphs are not already formatted
61 2157095 : if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
62 0 : && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
63 0 : if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
64 0 : ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
65 :
66 : // insert kashidas where requested by the formatting array
67 2157095 : if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
68 : {
69 0 : int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
70 0 : if( nKashidaIndex != 0 )
71 : {
72 0 : const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
73 0 : KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
74 : // TODO: kashida-GSUB/GPOS
75 : }
76 : }
77 2157095 : }
78 :
79 2344 : void ServerFontLayout::setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos,
80 : bool bRightToLeft)
81 : {
82 2344 : if (nCharPos < 0)
83 2344 : return;
84 :
85 : using namespace ::com::sun::star;
86 :
87 2344 : if (!mxBreak.is())
88 2024 : mxBreak = vcl::unohelper::CreateBreakIterator();
89 :
90 2344 : lang::Locale aLocale(rArgs.maLanguageTag.getLocale());
91 :
92 : //if position nCharPos is missing in the font, grab the entire grapheme and
93 : //mark all glyphs as missing so the whole thing is rendered with the same
94 : //font
95 4688 : OUString aRun(rArgs.mpStr);
96 : sal_Int32 nDone;
97 : sal_Int32 nGraphemeStartPos =
98 2344 : mxBreak->previousCharacters(aRun, nCharPos+1, aLocale,
99 2344 : i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
100 : sal_Int32 nGraphemeEndPos =
101 2344 : mxBreak->nextCharacters(aRun, nCharPos, aLocale,
102 2344 : i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
103 :
104 4688 : rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft);
105 : }
106 :
107 0 : std::ostream &operator <<(std::ostream& s, ServerFont* pFont)
108 : {
109 : #ifndef SAL_LOG_INFO
110 : (void) pFont;
111 : #else
112 : FT_Face aFace = pFont->GetFtFace();
113 : const char* pName = FT_Get_Postscript_Name(aFace);
114 : if (pName)
115 : s << pName;
116 : else
117 : s << pFont->GetFontFileName();
118 : #endif
119 0 : return s;
120 : }
121 :
122 29926 : static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData)
123 : {
124 : char pTagName[5];
125 29926 : pTagName[0] = (char)(nTableTag >> 24);
126 29926 : pTagName[1] = (char)(nTableTag >> 16);
127 29926 : pTagName[2] = (char)(nTableTag >> 8);
128 29926 : pTagName[3] = (char)(nTableTag);
129 29926 : pTagName[4] = 0;
130 :
131 29926 : ServerFont* pFont = (ServerFont*) pUserData;
132 :
133 : SAL_INFO("vcl.harfbuzz", "getFontTable(" << pFont << ", " << pTagName << ")");
134 :
135 : sal_uLong nLength;
136 29926 : const unsigned char* pBuffer = pFont->GetTable(pTagName, &nLength);
137 :
138 29926 : hb_blob_t* pBlob = NULL;
139 29926 : if (pBuffer != NULL)
140 21611 : pBlob = hb_blob_create((const char*) pBuffer, nLength, HB_MEMORY_MODE_READONLY, (void*) pBuffer, NULL);
141 :
142 29926 : return pBlob;
143 : }
144 :
145 41571049 : static hb_bool_t getFontGlyph(hb_font_t* /*font*/, void* pFontData,
146 : hb_codepoint_t ch, hb_codepoint_t vs,
147 : hb_codepoint_t* nGlyphIndex,
148 : void* /*pUserData*/)
149 : {
150 41571049 : ServerFont* pFont = (ServerFont*) pFontData;
151 41571049 : *nGlyphIndex = pFont->GetRawGlyphIndex(ch, vs);
152 :
153 41571049 : return *nGlyphIndex != 0;
154 : }
155 :
156 41530230 : static hb_position_t getGlyphAdvanceH(hb_font_t* /*font*/, void* pFontData,
157 : hb_codepoint_t nGlyphIndex,
158 : void* /*pUserData*/)
159 : {
160 41530230 : ServerFont* pFont = (ServerFont*) pFontData;
161 41530230 : const GlyphMetric& rGM = pFont->GetGlyphMetric(nGlyphIndex);
162 41530230 : return rGM.GetCharWidth() << 6;
163 : }
164 :
165 0 : static hb_position_t getGlyphAdvanceV(hb_font_t* /*font*/, void* /*pFontData*/,
166 : hb_codepoint_t /*nGlyphIndex*/,
167 : void* /*pUserData*/)
168 : {
169 : // XXX: vertical metrics
170 0 : return 0;
171 : }
172 :
173 124468374 : static hb_bool_t getGlyphOriginH(hb_font_t* /*font*/, void* /*pFontData*/,
174 : hb_codepoint_t /*nGlyphIndex*/,
175 : hb_position_t* /*x*/, hb_position_t* /*y*/,
176 : void* /*pUserData*/)
177 : {
178 : // the horizontal origin is always (0, 0)
179 124468374 : return true;
180 : }
181 :
182 0 : static hb_bool_t getGlyphOriginV(hb_font_t* /*font*/, void* /*pFontData*/,
183 : hb_codepoint_t /*nGlyphIndex*/,
184 : hb_position_t* /*x*/, hb_position_t* /*y*/,
185 : void* /*pUserData*/)
186 : {
187 : // XXX: vertical origin
188 0 : return true;
189 : }
190 :
191 54282 : static hb_position_t getGlyphKerningH(hb_font_t* /*font*/, void* pFontData,
192 : hb_codepoint_t nGlyphIndex1, hb_codepoint_t nGlyphIndex2,
193 : void* /*pUserData*/)
194 : {
195 : // This callback is for old style 'kern' table, GPOS kerning is handled by HarfBuzz directly
196 :
197 54282 : ServerFont* pFont = (ServerFont*) pFontData;
198 54282 : FT_Face aFace = pFont->GetFtFace();
199 :
200 : SAL_INFO("vcl.harfbuzz", "getGlyphKerningH(" << pFont << ", " << nGlyphIndex1 << ", " << nGlyphIndex2 << ")");
201 :
202 : FT_Error error;
203 : FT_Vector kerning;
204 : hb_position_t ret;
205 :
206 54282 : error = FT_Get_Kerning(aFace, nGlyphIndex1, nGlyphIndex2, FT_KERNING_DEFAULT, &kerning);
207 54282 : if (error)
208 0 : ret = 0;
209 : else
210 54282 : ret = kerning.x;
211 :
212 54282 : return ret;
213 : }
214 :
215 0 : static hb_position_t getGlyphKerningV(hb_font_t* /*font*/, void* /*pFontData*/,
216 : hb_codepoint_t /*nGlyphIndex1*/, hb_codepoint_t /*nGlyphIndex2*/,
217 : void* /*pUserData*/)
218 : {
219 : // XXX vertical kerning
220 0 : return 0;
221 : }
222 :
223 0 : static hb_bool_t getGlyphExtents(hb_font_t* /*font*/, void* pFontData,
224 : hb_codepoint_t nGlyphIndex,
225 : hb_glyph_extents_t* pExtents,
226 : void* /*pUserData*/)
227 : {
228 0 : ServerFont* pFont = (ServerFont*) pFontData;
229 0 : FT_Face aFace = pFont->GetFtFace();
230 :
231 : SAL_INFO("vcl.harfbuzz", "getGlyphExtents(" << pFont << ", " << nGlyphIndex << ")");
232 :
233 : FT_Error error;
234 0 : error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
235 0 : if (!error)
236 : {
237 0 : pExtents->x_bearing = aFace->glyph->metrics.horiBearingX;
238 0 : pExtents->y_bearing = aFace->glyph->metrics.horiBearingY;
239 0 : pExtents->width = aFace->glyph->metrics.width;
240 0 : pExtents->height = -aFace->glyph->metrics.height;
241 : }
242 :
243 0 : return !error;
244 : }
245 :
246 0 : static hb_bool_t getGlyphContourPoint(hb_font_t* /*font*/, void* pFontData,
247 : hb_codepoint_t nGlyphIndex, unsigned int nPointIndex,
248 : hb_position_t *x, hb_position_t *y,
249 : void* /*pUserData*/)
250 : {
251 0 : bool ret = false;
252 0 : ServerFont* pFont = (ServerFont*) pFontData;
253 0 : FT_Face aFace = pFont->GetFtFace();
254 :
255 : SAL_INFO("vcl.harfbuzz", "getGlyphContourPoint(" << pFont << ", " << nGlyphIndex << ", " << nPointIndex << ")");
256 :
257 : FT_Error error;
258 0 : error = FT_Load_Glyph(aFace, nGlyphIndex, FT_LOAD_DEFAULT);
259 0 : if (!error)
260 : {
261 0 : if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
262 : {
263 0 : if (nPointIndex < (unsigned int) aFace->glyph->outline.n_points)
264 : {
265 0 : *x = aFace->glyph->outline.points[nPointIndex].x;
266 0 : *y = aFace->glyph->outline.points[nPointIndex].y;
267 0 : ret = true;
268 : }
269 : }
270 : }
271 :
272 0 : return ret;
273 : }
274 :
275 290 : static hb_font_funcs_t* getFontFuncs(void)
276 : {
277 290 : static hb_font_funcs_t* funcs = hb_font_funcs_create();
278 :
279 290 : hb_font_funcs_set_glyph_func (funcs, getFontGlyph, NULL, NULL);
280 290 : hb_font_funcs_set_glyph_h_advance_func (funcs, getGlyphAdvanceH, NULL, NULL);
281 290 : hb_font_funcs_set_glyph_v_advance_func (funcs, getGlyphAdvanceV, NULL, NULL);
282 290 : hb_font_funcs_set_glyph_h_origin_func (funcs, getGlyphOriginH, NULL, NULL);
283 290 : hb_font_funcs_set_glyph_v_origin_func (funcs, getGlyphOriginV, NULL, NULL);
284 290 : hb_font_funcs_set_glyph_h_kerning_func (funcs, getGlyphKerningH, NULL, NULL);
285 290 : hb_font_funcs_set_glyph_v_kerning_func (funcs, getGlyphKerningV, NULL, NULL);
286 290 : hb_font_funcs_set_glyph_extents_func (funcs, getGlyphExtents, NULL, NULL);
287 290 : hb_font_funcs_set_glyph_contour_point_func (funcs, getGlyphContourPoint, NULL, NULL);
288 :
289 290 : return funcs;
290 : }
291 :
292 : // Disabled Unicode compatibility decomposition, see fdo#66715
293 2344 : static unsigned int unicodeDecomposeCompatibility(hb_unicode_funcs_t* /*ufuncs*/,
294 : hb_codepoint_t /*u*/,
295 : hb_codepoint_t* /*decomposed*/,
296 : void* /*user_data*/)
297 : {
298 2344 : return 0;
299 : }
300 :
301 290 : static hb_unicode_funcs_t* getUnicodeFuncs(void)
302 : {
303 290 : static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
304 290 : hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, NULL, NULL);
305 290 : return ufuncs;
306 : }
307 :
308 : class HbLayoutEngine : public ServerFontLayoutEngine
309 : {
310 : private:
311 : hb_script_t maHbScript;
312 : hb_face_t* mpHbFace;
313 : int mnUnitsPerEM;
314 :
315 : public:
316 : HbLayoutEngine(ServerFont&);
317 : virtual ~HbLayoutEngine();
318 :
319 : virtual bool layout(ServerFontLayout&, ImplLayoutArgs&) SAL_OVERRIDE;
320 : };
321 :
322 7482 : HbLayoutEngine::HbLayoutEngine(ServerFont& rServerFont)
323 : : maHbScript(HB_SCRIPT_INVALID),
324 : mpHbFace(NULL),
325 7482 : mnUnitsPerEM(0)
326 : {
327 7482 : FT_Face aFtFace = rServerFont.GetFtFace();
328 7482 : mnUnitsPerEM = rServerFont.GetEmUnits();
329 :
330 7482 : mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, NULL);
331 7482 : hb_face_set_index(mpHbFace, aFtFace->face_index);
332 7482 : hb_face_set_upem(mpHbFace, mnUnitsPerEM);
333 7482 : }
334 :
335 22446 : HbLayoutEngine::~HbLayoutEngine()
336 : {
337 7482 : hb_face_destroy(mpHbFace);
338 14964 : }
339 :
340 : struct HbScriptRun
341 : {
342 : int32_t mnMin;
343 : int32_t mnEnd;
344 : hb_script_t maScript;
345 :
346 2140250 : HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript)
347 : : mnMin(nMin), mnEnd(nEnd),
348 2140250 : maScript(hb_icu_script_to_script(aScript))
349 2140250 : {}
350 : };
351 :
352 : typedef std::vector<HbScriptRun> HbScriptRuns;
353 :
354 2156373 : bool HbLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
355 : {
356 2156373 : ServerFont& rFont = rLayout.GetServerFont();
357 2156373 : FT_Face aFtFace = rFont.GetFtFace();
358 :
359 : SAL_INFO("vcl.harfbuzz", "layout(" << this << ",rArgs=" << rArgs << ")");
360 :
361 2156373 : static hb_font_funcs_t* pHbFontFuncs = getFontFuncs();
362 :
363 2156373 : hb_font_t *pHbFont = hb_font_create(mpHbFace);
364 2156373 : hb_font_set_funcs(pHbFont, pHbFontFuncs, &rFont, NULL);
365 : hb_font_set_scale(pHbFont,
366 2156373 : ((uint64_t) aFtFace->size->metrics.x_scale * (uint64_t) mnUnitsPerEM) >> 16,
367 4312746 : ((uint64_t) aFtFace->size->metrics.y_scale * (uint64_t) mnUnitsPerEM) >> 16);
368 2156373 : hb_font_set_ppem(pHbFont, aFtFace->size->metrics.x_ppem, aFtFace->size->metrics.y_ppem);
369 :
370 : // allocate temporary arrays, note: round to even
371 2156373 : int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1;
372 :
373 2156373 : rLayout.Reserve(nGlyphCapacity);
374 :
375 2156373 : vcl::ScriptRun aScriptRun(reinterpret_cast<const UChar *>(rArgs.mpStr), rArgs.mnLength);
376 :
377 2156373 : Point aCurrPos(0, 0);
378 : while (true)
379 : {
380 : int nBidiMinRunPos, nBidiEndRunPos;
381 : bool bRightToLeft;
382 4296109 : if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft))
383 2156373 : break;
384 :
385 : // Find script subruns.
386 2139736 : int nCurrentPos = nBidiMinRunPos;
387 2139736 : HbScriptRuns aScriptSubRuns;
388 2139736 : while (aScriptRun.next())
389 : {
390 2140328 : if (aScriptRun.getScriptStart() <= nCurrentPos && aScriptRun.getScriptEnd() > nCurrentPos)
391 2139736 : break;
392 : }
393 :
394 6419722 : while (nCurrentPos < nBidiEndRunPos)
395 : {
396 2140250 : int32_t nMinRunPos = nCurrentPos;
397 2140250 : int32_t nEndRunPos = std::min(aScriptRun.getScriptEnd(), nBidiEndRunPos);
398 2140250 : HbScriptRun aRun(nMinRunPos, nEndRunPos, aScriptRun.getScriptCode());
399 2140250 : aScriptSubRuns.push_back(aRun);
400 :
401 2140250 : nCurrentPos = nEndRunPos;
402 2140250 : aScriptRun.next();
403 : }
404 :
405 : // RTL subruns should be reversed to ensure that final glyph order is
406 : // correct.
407 2139736 : if (bRightToLeft)
408 793 : std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end());
409 :
410 2139736 : aScriptRun.reset();
411 :
412 4279986 : for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it)
413 : {
414 2140250 : int nMinRunPos = it->mnMin;
415 2140250 : int nEndRunPos = it->mnEnd;
416 2140250 : int nRunLen = nEndRunPos - nMinRunPos;
417 2140250 : maHbScript = it->maScript;
418 :
419 2140250 : OString sLanguage = OUStringToOString(rArgs.maLanguageTag.getLanguage(), RTL_TEXTENCODING_UTF8);
420 :
421 2140250 : static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
422 :
423 2140250 : int nHbFlags = HB_BUFFER_FLAGS_DEFAULT;
424 2140250 : if (nMinRunPos == 0)
425 1712843 : nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */
426 2140250 : if (nEndRunPos == rArgs.mnLength)
427 1792542 : nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */
428 :
429 2140250 : hb_buffer_t *pHbBuffer = hb_buffer_create();
430 2140250 : hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
431 2140250 : hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
432 2140250 : hb_buffer_set_script(pHbBuffer, maHbScript);
433 2140250 : hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1));
434 2140250 : hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags);
435 2140250 : hb_buffer_add_utf16(pHbBuffer, rArgs.mpStr, rArgs.mnLength, nMinRunPos, nRunLen);
436 2140250 : hb_shape(pHbFont, pHbBuffer, NULL, 0);
437 :
438 2140250 : int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
439 2140250 : hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, NULL);
440 2140250 : hb_glyph_position_t *pHbPositions = hb_buffer_get_glyph_positions(pHbBuffer, NULL);
441 :
442 43670710 : for (int i = 0; i < nRunGlyphCount; ++i) {
443 41530460 : int32_t nGlyphIndex = pHbGlyphInfos[i].codepoint;
444 41530460 : int32_t nCharPos = pHbGlyphInfos[i].cluster;
445 :
446 : // if needed request glyph fallback by updating LayoutArgs
447 41530460 : if (!nGlyphIndex)
448 : {
449 2344 : rLayout.setNeedFallback(rArgs, nCharPos, bRightToLeft);
450 2344 : if (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)
451 52 : continue;
452 : }
453 :
454 : // apply vertical flags and glyph substitution
455 : // XXX: Use HB_DIRECTION_TTB above and apply whatever flags magic
456 : // FixupGlyphIndex() is doing, minus the GSUB part.
457 41530408 : if (nCharPos >= 0)
458 : {
459 41530408 : sal_UCS4 aChar = rArgs.mpStr[nCharPos];
460 41530408 : nGlyphIndex = rFont.FixupGlyphIndex(nGlyphIndex, aChar);
461 : }
462 :
463 41530408 : bool bInCluster = false;
464 41530408 : if (i > 0 && pHbGlyphInfos[i].cluster == pHbGlyphInfos[i - 1].cluster)
465 16 : bInCluster = true;
466 :
467 41530408 : long nGlyphFlags = 0;
468 41530408 : if (bRightToLeft)
469 1351 : nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
470 :
471 41530408 : if (bInCluster)
472 16 : nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
473 :
474 : // The whole IS_DIACRITIC concept is a stupid hack that was
475 : // introduced ages ago to work around the utter brokenness of the
476 : // way justification adjustments are applied (the DXArray fiasco).
477 : // Since it is such a stupid hack, there is no sane way to directly
478 : // map to concepts of the "outside" world, so we do some rather
479 : // ugly hacks:
480 : // * If the font has a GDEF table, we check for glyphs with mark
481 : // glyph class which is sensible, except that some fonts
482 : // (fdo#70968) assign mark class to spacing marks (which is wrong
483 : // but usually harmless), so we try to sniff what HarfBuzz thinks
484 : // about this glyph by checking if it gives it a zero advance
485 : // width.
486 : // * If the font has no GDEF table, we just check if the glyph has
487 : // zero advance width, but this is stupid and can be wrong. A
488 : // better way would to check the character's Unicode combining
489 : // class, but unfortunately glyph gives combining marks the
490 : // cluster value of its base character, so nCharPos will be
491 : // pointing to the wrong character (but HarfBuzz might change
492 : // this in the future).
493 41530408 : bool bDiacritic = false;
494 41530408 : if (hb_ot_layout_has_glyph_classes(mpHbFace))
495 : {
496 : // the font has GDEF table
497 41470068 : bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
498 41470068 : if (bMark && pHbPositions[i].x_advance == 0)
499 16 : bDiacritic = true;
500 : }
501 : else
502 : {
503 : // the font lacks GDEF table
504 60340 : if (pHbPositions[i].x_advance == 0)
505 8 : bDiacritic = true;
506 : }
507 :
508 41530408 : if (bDiacritic)
509 24 : nGlyphFlags |= GlyphItem::IS_DIACRITIC;
510 :
511 41530408 : int32_t nXOffset = pHbPositions[i].x_offset >> 6;
512 41530408 : int32_t nYOffset = pHbPositions[i].y_offset >> 6;
513 41530408 : int32_t nXAdvance = pHbPositions[i].x_advance >> 6;
514 41530408 : int32_t nYAdvance = pHbPositions[i].y_advance >> 6;
515 :
516 41530408 : Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
517 41530408 : const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset);
518 41530408 : rLayout.AppendGlyph(aGI);
519 :
520 41530408 : aCurrPos.X() += nXAdvance;
521 41530408 : aCurrPos.Y() += nYAdvance;
522 : }
523 :
524 2140250 : hb_buffer_destroy(pHbBuffer);
525 2140250 : }
526 2139736 : }
527 :
528 2156373 : hb_font_destroy(pHbFont);
529 :
530 : // sort glyphs in visual order
531 : // and then in logical order (e.g. diacritics after cluster start)
532 : // XXX: why?
533 2156373 : rLayout.SortGlyphItems();
534 :
535 : // determine need for kashida justification
536 2156373 : if((rArgs.mpDXArray || rArgs.mnLayoutWidth)
537 58988 : && ((maHbScript == HB_SCRIPT_ARABIC) || (maHbScript == HB_SCRIPT_SYRIAC)))
538 0 : rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
539 :
540 2156373 : return true;
541 : }
542 :
543 2156373 : ServerFontLayoutEngine* ServerFont::GetLayoutEngine()
544 : {
545 : // find best layout engine for font, platform, script and language
546 2156373 : if (!mpLayoutEngine) {
547 7482 : mpLayoutEngine = new HbLayoutEngine(*this);
548 : }
549 2156373 : return mpLayoutEngine;
550 1233 : }
551 :
552 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|