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