19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
39f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file
59f62ea84SAndrew Rist * distributed with this work for additional information
69f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file
79f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at
109f62ea84SAndrew Rist *
119f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist *
139f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist * software distributed under the License is distributed on an
159f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist * KIND, either express or implied. See the License for the
179f62ea84SAndrew Rist * specific language governing permissions and limitations
189f62ea84SAndrew Rist * under the License.
199f62ea84SAndrew Rist *
209f62ea84SAndrew Rist *************************************************************/
219f62ea84SAndrew Rist
229f62ea84SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir #define ENABLE_ICU_LAYOUT
28cdf0e10cSrcweir #include <gcach_ftyp.hxx>
29cdf0e10cSrcweir #include <sallayout.hxx>
30cdf0e10cSrcweir #include <salgdi.hxx>
31cdf0e10cSrcweir
32cdf0e10cSrcweir #include <vcl/svapp.hxx>
33cdf0e10cSrcweir
34cdf0e10cSrcweir #include <sal/alloca.h>
35cdf0e10cSrcweir
36cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
37cdf0e10cSrcweir #include <cstdio>
38cdf0e10cSrcweir #endif
39cdf0e10cSrcweir #include <rtl/instance.hxx>
40cdf0e10cSrcweir
41cdf0e10cSrcweir namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; }
42cdf0e10cSrcweir
43cdf0e10cSrcweir // =======================================================================
44cdf0e10cSrcweir // layout implementation for ServerFont
45cdf0e10cSrcweir // =======================================================================
46cdf0e10cSrcweir
ServerFontLayout(ServerFont & rFont)47cdf0e10cSrcweir ServerFontLayout::ServerFontLayout( ServerFont& rFont )
48cdf0e10cSrcweir : mrServerFont( rFont )
49cdf0e10cSrcweir {}
50cdf0e10cSrcweir
DrawText(SalGraphics & rSalGraphics) const51cdf0e10cSrcweir void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const
52cdf0e10cSrcweir {
53cdf0e10cSrcweir rSalGraphics.DrawServerFontLayout( *this );
54cdf0e10cSrcweir }
55cdf0e10cSrcweir
56cdf0e10cSrcweir // -----------------------------------------------------------------------
57cdf0e10cSrcweir
LayoutText(ImplLayoutArgs & rArgs)58cdf0e10cSrcweir bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs )
59cdf0e10cSrcweir {
60cdf0e10cSrcweir ServerFontLayoutEngine* pLE = NULL;
61cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) )
62cdf0e10cSrcweir pLE = mrServerFont.GetLayoutEngine();
63cdf0e10cSrcweir if( !pLE )
64cdf0e10cSrcweir pLE = &SimpleLayoutEngine::get();
65cdf0e10cSrcweir
66cdf0e10cSrcweir bool bRet = (*pLE)( *this, rArgs );
67cdf0e10cSrcweir return bRet;
68cdf0e10cSrcweir }
69cdf0e10cSrcweir
70cdf0e10cSrcweir // -----------------------------------------------------------------------
71cdf0e10cSrcweir
AdjustLayout(ImplLayoutArgs & rArgs)72cdf0e10cSrcweir void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
73cdf0e10cSrcweir {
74cdf0e10cSrcweir GenericSalLayout::AdjustLayout( rArgs );
75cdf0e10cSrcweir
76cdf0e10cSrcweir // apply asian kerning if the glyphs are not already formatted
77cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN)
78cdf0e10cSrcweir && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) )
79cdf0e10cSrcweir if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) )
80cdf0e10cSrcweir ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength );
81cdf0e10cSrcweir
82cdf0e10cSrcweir // insert kashidas where requested by the formatting array
83cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray )
84cdf0e10cSrcweir {
85cdf0e10cSrcweir int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 );
86cdf0e10cSrcweir if( nKashidaIndex != 0 )
87cdf0e10cSrcweir {
88cdf0e10cSrcweir const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex );
89cdf0e10cSrcweir KashidaJustify( nKashidaIndex, rGM.GetCharWidth() );
90cdf0e10cSrcweir // TODO: kashida-GSUB/GPOS
91cdf0e10cSrcweir }
92cdf0e10cSrcweir }
93cdf0e10cSrcweir }
94cdf0e10cSrcweir
95cdf0e10cSrcweir // =======================================================================
96cdf0e10cSrcweir
operator ()(ServerFontLayout & rLayout,ImplLayoutArgs & rArgs)97cdf0e10cSrcweir bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
98cdf0e10cSrcweir {
99cdf0e10cSrcweir FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont());
100cdf0e10cSrcweir
101cdf0e10cSrcweir Point aNewPos( 0, 0 );
102*248a599fSHerbert Dürr sal_GlyphId nOldGlyphId( GF_DROPPED);
103cdf0e10cSrcweir int nGlyphWidth = 0;
104cdf0e10cSrcweir GlyphItem aPrevItem;
105cdf0e10cSrcweir bool bRightToLeft;
106cdf0e10cSrcweir for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
107cdf0e10cSrcweir {
108cdf0e10cSrcweir sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
109cdf0e10cSrcweir if( (cChar >= 0xD800) && (cChar <= 0xDFFF) )
110cdf0e10cSrcweir {
111cdf0e10cSrcweir if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
112cdf0e10cSrcweir continue;
113cdf0e10cSrcweir cChar = 0x10000 + ((cChar - 0xD800) << 10)
114cdf0e10cSrcweir + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00);
115cdf0e10cSrcweir }
116cdf0e10cSrcweir
117cdf0e10cSrcweir if( bRightToLeft )
118cdf0e10cSrcweir cChar = GetMirroredChar( cChar );
119*248a599fSHerbert Dürr sal_GlyphId aGlyphId = rFont.GetGlyphIndex( cChar );
120cdf0e10cSrcweir // when glyph fallback is needed update LayoutArgs
121*248a599fSHerbert Dürr if( !aGlyphId ) {
122cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRightToLeft );
123cdf0e10cSrcweir if( cChar >= 0x10000 ) // handle surrogate pairs
124cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRightToLeft );
125cdf0e10cSrcweir }
126cdf0e10cSrcweir
127cdf0e10cSrcweir // apply pair kerning to prev glyph if requested
128cdf0e10cSrcweir if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
129cdf0e10cSrcweir {
130*248a599fSHerbert Dürr int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, aGlyphId );
131cdf0e10cSrcweir nGlyphWidth += nKernValue;
132cdf0e10cSrcweir aPrevItem.mnNewWidth = nGlyphWidth;
133cdf0e10cSrcweir }
134cdf0e10cSrcweir
135cdf0e10cSrcweir // finish previous glyph
136*248a599fSHerbert Dürr if( nOldGlyphId != GF_DROPPED )
137cdf0e10cSrcweir rLayout.AppendGlyph( aPrevItem );
138cdf0e10cSrcweir aNewPos.X() += nGlyphWidth;
139cdf0e10cSrcweir
140cdf0e10cSrcweir // prepare GlyphItem for appending it in next round
141*248a599fSHerbert Dürr nOldGlyphId = aGlyphId;
142*248a599fSHerbert Dürr const GlyphMetric& rGM = rFont.GetGlyphMetric( aGlyphId );
143cdf0e10cSrcweir nGlyphWidth = rGM.GetCharWidth();
144cdf0e10cSrcweir int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
145*248a599fSHerbert Dürr aPrevItem = GlyphItem( nCharPos, aGlyphId, aNewPos, nGlyphFlags, nGlyphWidth );
146cdf0e10cSrcweir }
147cdf0e10cSrcweir
148cdf0e10cSrcweir // append last glyph item if any
149*248a599fSHerbert Dürr if( nOldGlyphId != GF_DROPPED )
150cdf0e10cSrcweir rLayout.AppendGlyph( aPrevItem );
151cdf0e10cSrcweir
152cdf0e10cSrcweir return true;
153cdf0e10cSrcweir }
154cdf0e10cSrcweir
155cdf0e10cSrcweir // =======================================================================
156cdf0e10cSrcweir // bridge to ICU LayoutEngine
157cdf0e10cSrcweir // =======================================================================
158cdf0e10cSrcweir
159cdf0e10cSrcweir #ifdef ENABLE_ICU_LAYOUT
160cdf0e10cSrcweir
161cdf0e10cSrcweir #define bool_t signed char
162cdf0e10cSrcweir
163cdf0e10cSrcweir // disable warnings in icu layout headers
164cdf0e10cSrcweir #if defined __SUNPRO_CC
165cdf0e10cSrcweir #pragma disable_warn
166cdf0e10cSrcweir #endif
167cdf0e10cSrcweir
168cdf0e10cSrcweir #include <layout/LayoutEngine.h>
169cdf0e10cSrcweir #include <layout/LEFontInstance.h>
170cdf0e10cSrcweir #include <layout/LEScripts.h>
171cdf0e10cSrcweir
172cdf0e10cSrcweir // enable warnings again
173cdf0e10cSrcweir #if defined __SUNPRO_CC
174cdf0e10cSrcweir #pragma enable_warn
175cdf0e10cSrcweir #endif
176cdf0e10cSrcweir
177cdf0e10cSrcweir #include <unicode/uscript.h>
178cdf0e10cSrcweir #include <unicode/ubidi.h>
179cdf0e10cSrcweir
180cdf0e10cSrcweir using namespace U_ICU_NAMESPACE;
181cdf0e10cSrcweir
182cdf0e10cSrcweir static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF;
183cdf0e10cSrcweir static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE;
184cdf0e10cSrcweir
185cdf0e10cSrcweir // -----------------------------------------------------------------------
186cdf0e10cSrcweir
187cdf0e10cSrcweir class IcuFontFromServerFont
188cdf0e10cSrcweir : public LEFontInstance
189cdf0e10cSrcweir {
190cdf0e10cSrcweir private:
191cdf0e10cSrcweir FreetypeServerFont& mrServerFont;
192cdf0e10cSrcweir
193cdf0e10cSrcweir public:
IcuFontFromServerFont(FreetypeServerFont & rFont)194cdf0e10cSrcweir IcuFontFromServerFont( FreetypeServerFont& rFont )
195cdf0e10cSrcweir : mrServerFont( rFont )
196cdf0e10cSrcweir {}
197cdf0e10cSrcweir
198cdf0e10cSrcweir virtual const void* getFontTable(LETag tableTag) const;
199cdf0e10cSrcweir virtual le_int32 getUnitsPerEM() const;
200cdf0e10cSrcweir virtual float getXPixelsPerEm() const;
201cdf0e10cSrcweir virtual float getYPixelsPerEm() const;
202cdf0e10cSrcweir virtual float getScaleFactorX() const;
203cdf0e10cSrcweir virtual float getScaleFactorY() const;
204cdf0e10cSrcweir
205cdf0e10cSrcweir using LEFontInstance::mapCharToGlyph;
206cdf0e10cSrcweir virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const;
207cdf0e10cSrcweir
208cdf0e10cSrcweir virtual le_int32 getAscent() const;
209cdf0e10cSrcweir virtual le_int32 getDescent() const;
210cdf0e10cSrcweir virtual le_int32 getLeading() const;
211cdf0e10cSrcweir
212cdf0e10cSrcweir virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const;
213cdf0e10cSrcweir virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const;
214cdf0e10cSrcweir };
215cdf0e10cSrcweir
216cdf0e10cSrcweir // -----------------------------------------------------------------------
217cdf0e10cSrcweir
getFontTable(LETag nICUTableTag) const218cdf0e10cSrcweir const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const
219cdf0e10cSrcweir {
220cdf0e10cSrcweir char pTagName[5];
221cdf0e10cSrcweir pTagName[0] = (char)(nICUTableTag >> 24);
222cdf0e10cSrcweir pTagName[1] = (char)(nICUTableTag >> 16);
223cdf0e10cSrcweir pTagName[2] = (char)(nICUTableTag >> 8);
224cdf0e10cSrcweir pTagName[3] = (char)(nICUTableTag);
225cdf0e10cSrcweir pTagName[4] = 0;
226cdf0e10cSrcweir
227cdf0e10cSrcweir sal_uLong nLength;
228cdf0e10cSrcweir const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength );
229cdf0e10cSrcweir #ifdef VERBOSE_DEBUG
230cdf0e10cSrcweir fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer);
231cdf0e10cSrcweir int mnHeight = mrServerFont.GetFontSelData().mnHeight;
232cdf0e10cSrcweir const char* pName = mrServerFont.GetFontFileName()->getStr();
233cdf0e10cSrcweir fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName );
234cdf0e10cSrcweir #endif
235cdf0e10cSrcweir return (const void*)pBuffer;
236cdf0e10cSrcweir }
237cdf0e10cSrcweir
238cdf0e10cSrcweir // -----------------------------------------------------------------------
239cdf0e10cSrcweir
getUnitsPerEM() const240cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getUnitsPerEM() const
241cdf0e10cSrcweir {
242cdf0e10cSrcweir return mrServerFont.GetEmUnits();
243cdf0e10cSrcweir }
244cdf0e10cSrcweir
245cdf0e10cSrcweir // -----------------------------------------------------------------------
246cdf0e10cSrcweir
getXPixelsPerEm() const247cdf0e10cSrcweir float IcuFontFromServerFont::getXPixelsPerEm() const
248cdf0e10cSrcweir {
249cdf0e10cSrcweir const ImplFontSelectData& r = mrServerFont.GetFontSelData();
250cdf0e10cSrcweir float fX = r.mnWidth ? r.mnWidth : r.mnHeight;
251cdf0e10cSrcweir return fX;
252cdf0e10cSrcweir }
253cdf0e10cSrcweir
254cdf0e10cSrcweir // -----------------------------------------------------------------------
255cdf0e10cSrcweir
getYPixelsPerEm() const256cdf0e10cSrcweir float IcuFontFromServerFont::getYPixelsPerEm() const
257cdf0e10cSrcweir {
258cdf0e10cSrcweir float fY = mrServerFont.GetFontSelData().mnHeight;
259cdf0e10cSrcweir return fY;
260cdf0e10cSrcweir }
261cdf0e10cSrcweir
262cdf0e10cSrcweir // -----------------------------------------------------------------------
263cdf0e10cSrcweir
getScaleFactorX() const264cdf0e10cSrcweir float IcuFontFromServerFont::getScaleFactorX() const
265cdf0e10cSrcweir {
266cdf0e10cSrcweir return 1.0;
267cdf0e10cSrcweir }
268cdf0e10cSrcweir
269cdf0e10cSrcweir // -----------------------------------------------------------------------
270cdf0e10cSrcweir
getScaleFactorY() const271cdf0e10cSrcweir float IcuFontFromServerFont::getScaleFactorY() const
272cdf0e10cSrcweir {
273cdf0e10cSrcweir return 1.0;
274cdf0e10cSrcweir }
275cdf0e10cSrcweir
276cdf0e10cSrcweir // -----------------------------------------------------------------------
277cdf0e10cSrcweir
mapCharToGlyph(LEUnicode32 ch) const278cdf0e10cSrcweir LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const
279cdf0e10cSrcweir {
280cdf0e10cSrcweir LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch );
281cdf0e10cSrcweir return nGlyphIndex;
282cdf0e10cSrcweir }
283cdf0e10cSrcweir
284cdf0e10cSrcweir // -----------------------------------------------------------------------
285cdf0e10cSrcweir
getAscent() const286cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getAscent() const
287cdf0e10cSrcweir {
288cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
289cdf0e10cSrcweir le_int32 nAscent = (+rMetrics.ascender + 32) >> 6;
290cdf0e10cSrcweir return nAscent;
291cdf0e10cSrcweir }
292cdf0e10cSrcweir
293cdf0e10cSrcweir // -----------------------------------------------------------------------
294cdf0e10cSrcweir
getDescent() const295cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getDescent() const
296cdf0e10cSrcweir {
297cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
298cdf0e10cSrcweir le_int32 nDescent = (-rMetrics.descender + 32) >> 6;
299cdf0e10cSrcweir return nDescent;
300cdf0e10cSrcweir }
301cdf0e10cSrcweir
302cdf0e10cSrcweir // -----------------------------------------------------------------------
303cdf0e10cSrcweir
getLeading() const304cdf0e10cSrcweir le_int32 IcuFontFromServerFont::getLeading() const
305cdf0e10cSrcweir {
306cdf0e10cSrcweir const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT();
307cdf0e10cSrcweir le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6;
308cdf0e10cSrcweir return nLeading;
309cdf0e10cSrcweir }
310cdf0e10cSrcweir
311cdf0e10cSrcweir // -----------------------------------------------------------------------
312cdf0e10cSrcweir
getGlyphAdvance(LEGlyphID nGlyphIndex,LEPoint & advance) const313cdf0e10cSrcweir void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex,
314cdf0e10cSrcweir LEPoint &advance ) const
315cdf0e10cSrcweir {
316cdf0e10cSrcweir if( (nGlyphIndex == ICU_MARKED_GLYPH)
317cdf0e10cSrcweir || (nGlyphIndex == ICU_DELETED_GLYPH) )
318cdf0e10cSrcweir {
319cdf0e10cSrcweir // deleted glyph or mark glyph has not advance
320cdf0e10cSrcweir advance.fX = 0;
321cdf0e10cSrcweir }
322cdf0e10cSrcweir else
323cdf0e10cSrcweir {
324cdf0e10cSrcweir const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex );
325cdf0e10cSrcweir advance.fX = rGM.GetCharWidth();
326cdf0e10cSrcweir }
327cdf0e10cSrcweir
328cdf0e10cSrcweir advance.fY = 0;
329cdf0e10cSrcweir }
330cdf0e10cSrcweir
331cdf0e10cSrcweir // -----------------------------------------------------------------------
332cdf0e10cSrcweir
getGlyphPoint(LEGlyphID,le_int32 pointNumber,LEPoint &) const333cdf0e10cSrcweir le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID,
334cdf0e10cSrcweir le_int32
335cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
336cdf0e10cSrcweir pointNumber
337cdf0e10cSrcweir #endif
338cdf0e10cSrcweir ,
339cdf0e10cSrcweir LEPoint& ) const
340cdf0e10cSrcweir {
341cdf0e10cSrcweir //TODO: replace dummy implementation
342cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
343cdf0e10cSrcweir fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber );
344cdf0e10cSrcweir #endif
345cdf0e10cSrcweir return false;
346cdf0e10cSrcweir }
347cdf0e10cSrcweir
348cdf0e10cSrcweir // =======================================================================
349cdf0e10cSrcweir
350cdf0e10cSrcweir class IcuLayoutEngine : public ServerFontLayoutEngine
351cdf0e10cSrcweir {
352cdf0e10cSrcweir private:
353cdf0e10cSrcweir IcuFontFromServerFont maIcuFont;
354cdf0e10cSrcweir
355cdf0e10cSrcweir le_int32 meScriptCode;
356cdf0e10cSrcweir LayoutEngine* mpIcuLE;
357cdf0e10cSrcweir
358cdf0e10cSrcweir public:
359cdf0e10cSrcweir IcuLayoutEngine( FreetypeServerFont& );
360cdf0e10cSrcweir virtual ~IcuLayoutEngine();
361cdf0e10cSrcweir
362cdf0e10cSrcweir virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& );
363cdf0e10cSrcweir };
364cdf0e10cSrcweir
365cdf0e10cSrcweir // -----------------------------------------------------------------------
366cdf0e10cSrcweir
IcuLayoutEngine(FreetypeServerFont & rServerFont)367cdf0e10cSrcweir IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont )
368cdf0e10cSrcweir : maIcuFont( rServerFont ),
369cdf0e10cSrcweir meScriptCode( USCRIPT_INVALID_CODE ),
370cdf0e10cSrcweir mpIcuLE( NULL )
371cdf0e10cSrcweir {}
372cdf0e10cSrcweir
373cdf0e10cSrcweir // -----------------------------------------------------------------------
374cdf0e10cSrcweir
~IcuLayoutEngine()375cdf0e10cSrcweir IcuLayoutEngine::~IcuLayoutEngine()
376cdf0e10cSrcweir {
377cdf0e10cSrcweir if( mpIcuLE )
378cdf0e10cSrcweir delete mpIcuLE;
379cdf0e10cSrcweir }
380cdf0e10cSrcweir
381cdf0e10cSrcweir // -----------------------------------------------------------------------
382cdf0e10cSrcweir
lcl_CharIsJoiner(sal_Unicode cChar)383cdf0e10cSrcweir static bool lcl_CharIsJoiner(sal_Unicode cChar)
384cdf0e10cSrcweir {
385cdf0e10cSrcweir return ((cChar == 0x200C) || (cChar == 0x200D));
386cdf0e10cSrcweir }
387cdf0e10cSrcweir
operator ()(ServerFontLayout & rLayout,ImplLayoutArgs & rArgs)388cdf0e10cSrcweir bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
389cdf0e10cSrcweir {
390cdf0e10cSrcweir LEUnicode* pIcuChars;
391cdf0e10cSrcweir if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) )
392cdf0e10cSrcweir pIcuChars = (LEUnicode*)rArgs.mpStr;
393cdf0e10cSrcweir else
394cdf0e10cSrcweir {
395cdf0e10cSrcweir // this conversion will only be needed when either
396cdf0e10cSrcweir // ICU's or OOo's unicodes stop being unsigned shorts
397cdf0e10cSrcweir // TODO: watch out for surrogates!
398cdf0e10cSrcweir pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) );
399cdf0e10cSrcweir for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic )
400cdf0e10cSrcweir pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] );
401cdf0e10cSrcweir }
402cdf0e10cSrcweir
403cdf0e10cSrcweir // allocate temporary arrays, note: round to even
404cdf0e10cSrcweir int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
405cdf0e10cSrcweir
406cdf0e10cSrcweir struct IcuPosition{ float fX, fY; };
407cdf0e10cSrcweir const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition);
408cdf0e10cSrcweir LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) );
409cdf0e10cSrcweir le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) );
410cdf0e10cSrcweir IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) );
411cdf0e10cSrcweir
412cdf0e10cSrcweir FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont());
413cdf0e10cSrcweir
414cdf0e10cSrcweir UErrorCode rcI18n = U_ZERO_ERROR;
415cdf0e10cSrcweir LEErrorCode rcIcu = LE_NO_ERROR;
416cdf0e10cSrcweir Point aNewPos( 0, 0 );
417cdf0e10cSrcweir for( int nGlyphCount = 0;; )
418cdf0e10cSrcweir {
419cdf0e10cSrcweir int nMinRunPos, nEndRunPos;
420cdf0e10cSrcweir bool bRightToLeft;
421cdf0e10cSrcweir if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
422cdf0e10cSrcweir break;
423cdf0e10cSrcweir
424cdf0e10cSrcweir // find matching script
425cdf0e10cSrcweir // TODO: split up bidi run into script runs
426cdf0e10cSrcweir le_int32 eScriptCode = -1;
427cdf0e10cSrcweir for( int i = nMinRunPos; i < nEndRunPos; ++i )
428cdf0e10cSrcweir {
429cdf0e10cSrcweir eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n );
430cdf0e10cSrcweir if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) )
431cdf0e10cSrcweir break;
432cdf0e10cSrcweir }
433cdf0e10cSrcweir if( eScriptCode < 0 ) // TODO: handle errors better
434cdf0e10cSrcweir eScriptCode = latnScriptCode;
435cdf0e10cSrcweir
436cdf0e10cSrcweir // get layout engine matching to this script
437cdf0e10cSrcweir // no engine change necessary if script is latin
438cdf0e10cSrcweir if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) )
439cdf0e10cSrcweir {
440cdf0e10cSrcweir // TODO: cache multiple layout engines when multiple scripts are used
441cdf0e10cSrcweir delete mpIcuLE;
442cdf0e10cSrcweir meScriptCode = eScriptCode;
443cdf0e10cSrcweir le_int32 eLangCode = 0; // TODO: get better value
444cdf0e10cSrcweir mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu );
445cdf0e10cSrcweir if( LE_FAILURE(rcIcu) )
446cdf0e10cSrcweir {
447cdf0e10cSrcweir delete mpIcuLE;
448cdf0e10cSrcweir mpIcuLE = NULL;
449cdf0e10cSrcweir }
450cdf0e10cSrcweir }
451cdf0e10cSrcweir
452cdf0e10cSrcweir // fall back to default layout if needed
453cdf0e10cSrcweir if( !mpIcuLE )
454cdf0e10cSrcweir break;
455cdf0e10cSrcweir
456cdf0e10cSrcweir // run ICU layout engine
457cdf0e10cSrcweir // TODO: get enough context, remove extra glyps below
458cdf0e10cSrcweir int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars,
459cdf0e10cSrcweir nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength,
460cdf0e10cSrcweir bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu );
461cdf0e10cSrcweir if( LE_FAILURE(rcIcu) )
462cdf0e10cSrcweir return false;
463cdf0e10cSrcweir
464cdf0e10cSrcweir // import layout info from icu
465cdf0e10cSrcweir mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu );
466cdf0e10cSrcweir mpIcuLE->getCharIndices( pCharIndices, rcIcu );
467cdf0e10cSrcweir mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu );
468cdf0e10cSrcweir mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed
469cdf0e10cSrcweir if( LE_FAILURE(rcIcu) )
470cdf0e10cSrcweir return false;
471cdf0e10cSrcweir
472cdf0e10cSrcweir // layout bidi/script runs and export them to a ServerFontLayout
473cdf0e10cSrcweir // convert results to GlyphItems
474cdf0e10cSrcweir int nLastCharPos = -1;
475cdf0e10cSrcweir int nClusterMinPos = -1;
476cdf0e10cSrcweir int nClusterMaxPos = -1;
477cdf0e10cSrcweir bool bClusterStart = true;
478cdf0e10cSrcweir int nFilteredRunGlyphCount = 0;
479cdf0e10cSrcweir const IcuPosition* pPos = pGlyphPositions;
480cdf0e10cSrcweir for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos )
481cdf0e10cSrcweir {
482cdf0e10cSrcweir LEGlyphID nGlyphIndex = pIcuGlyphs[i];
483cdf0e10cSrcweir // ignore glyphs which were marked or deleted by ICU
484cdf0e10cSrcweir if( (nGlyphIndex == ICU_MARKED_GLYPH)
485cdf0e10cSrcweir || (nGlyphIndex == ICU_DELETED_GLYPH) )
486cdf0e10cSrcweir continue;
487cdf0e10cSrcweir
488cdf0e10cSrcweir // adjust the relative char pos
489cdf0e10cSrcweir int nCharPos = pCharIndices[i];
490cdf0e10cSrcweir if( nCharPos >= 0 ) {
491cdf0e10cSrcweir nCharPos += nMinRunPos;
492cdf0e10cSrcweir // ICU seems to return bad pCharIndices
493cdf0e10cSrcweir // for some combinations of ICU+font+text
494cdf0e10cSrcweir // => better give up now than crash later
495cdf0e10cSrcweir if( nCharPos >= nEndRunPos )
496cdf0e10cSrcweir continue;
497cdf0e10cSrcweir }
498cdf0e10cSrcweir
499cdf0e10cSrcweir // if needed request glyph fallback by updating LayoutArgs
500cdf0e10cSrcweir if( !nGlyphIndex )
501cdf0e10cSrcweir {
502cdf0e10cSrcweir if( nCharPos >= 0 )
503cdf0e10cSrcweir {
504cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRightToLeft );
505cdf0e10cSrcweir if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) )
506cdf0e10cSrcweir rArgs.NeedFallback( nCharPos-1, bRightToLeft );
507cdf0e10cSrcweir else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) )
508cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRightToLeft );
509cdf0e10cSrcweir }
510cdf0e10cSrcweir
511cdf0e10cSrcweir if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
512cdf0e10cSrcweir continue;
513cdf0e10cSrcweir }
514cdf0e10cSrcweir
515cdf0e10cSrcweir
516cdf0e10cSrcweir // apply vertical flags, etc.
517cdf0e10cSrcweir bool bDiacritic = false;
518cdf0e10cSrcweir if( nCharPos >= 0 )
519cdf0e10cSrcweir {
520cdf0e10cSrcweir sal_UCS4 aChar = rArgs.mpStr[ nCharPos ];
521cdf0e10cSrcweir #if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0
522cdf0e10cSrcweir if( (aChar >= 0xD800) && (aChar <= 0xDFFF) )
523cdf0e10cSrcweir {
524cdf0e10cSrcweir if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed
525cdf0e10cSrcweir continue;
526cdf0e10cSrcweir // calculate unicode scalar value of surrogate pair
527cdf0e10cSrcweir aChar = 0x10000 + ((aChar - 0xD800) << 10);
528cdf0e10cSrcweir sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ];
529cdf0e10cSrcweir aChar += aLow & 0x03FF;
530cdf0e10cSrcweir }
531cdf0e10cSrcweir #endif
532cdf0e10cSrcweir nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar );
533cdf0e10cSrcweir
534cdf0e10cSrcweir // #i99367# HACK: try to detect all diacritics
535cdf0e10cSrcweir if( aChar>=0x0300 && aChar<0x2100 )
536cdf0e10cSrcweir bDiacritic = IsDiacritic( aChar );
537cdf0e10cSrcweir }
538cdf0e10cSrcweir
539cdf0e10cSrcweir // get glyph position and its metrics
540cdf0e10cSrcweir aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
541cdf0e10cSrcweir const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
542cdf0e10cSrcweir int nGlyphWidth = rGM.GetCharWidth();
5434bb59e41SHerbert Dürr int nNewWidth = nGlyphWidth;
544cdf0e10cSrcweir if( nGlyphWidth <= 0 )
545cdf0e10cSrcweir bDiacritic |= true;
546cdf0e10cSrcweir // #i99367# force all diacritics to zero width
547cdf0e10cSrcweir // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth
5484bb59e41SHerbert Dürr else if( bDiacritic )
5494bb59e41SHerbert Dürr nGlyphWidth = nNewWidth = 0;
5504bb59e41SHerbert Dürr else
5514bb59e41SHerbert Dürr {
5524bb59e41SHerbert Dürr // Hack, find next +ve width glyph and calculate current
5534bb59e41SHerbert Dürr // glyph width by substracting the two posituons
5544bb59e41SHerbert Dürr const IcuPosition* pNextPos = pPos+1;
5554bb59e41SHerbert Dürr for ( int j = i + 1; j <= nRawRunGlyphCount; ++j, ++pNextPos )
5564bb59e41SHerbert Dürr {
5574bb59e41SHerbert Dürr if ( j == nRawRunGlyphCount )
5584bb59e41SHerbert Dürr {
5594bb59e41SHerbert Dürr nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
5604bb59e41SHerbert Dürr break;
5614bb59e41SHerbert Dürr }
5624bb59e41SHerbert Dürr
5634bb59e41SHerbert Dürr LEGlyphID nNextGlyphIndex = pIcuGlyphs[j];
5644bb59e41SHerbert Dürr if( (nNextGlyphIndex == ICU_MARKED_GLYPH)
5654bb59e41SHerbert Dürr || (nNextGlyphIndex == ICU_DELETED_GLYPH) )
5664bb59e41SHerbert Dürr continue;
5674bb59e41SHerbert Dürr
5684bb59e41SHerbert Dürr const GlyphMetric& rNextGM = rFont.GetGlyphMetric( nNextGlyphIndex );
5694bb59e41SHerbert Dürr int nNextGlyphWidth = rNextGM.GetCharWidth();
5704bb59e41SHerbert Dürr if ( nNextGlyphWidth > 0 )
5714bb59e41SHerbert Dürr {
5724bb59e41SHerbert Dürr nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX);
5734bb59e41SHerbert Dürr break;
5744bb59e41SHerbert Dürr }
5754bb59e41SHerbert Dürr }
5764bb59e41SHerbert Dürr }
577cdf0e10cSrcweir
578cdf0e10cSrcweir // heuristic to detect glyph clusters
579cdf0e10cSrcweir bool bInCluster = true;
580cdf0e10cSrcweir if( nLastCharPos == -1 )
581cdf0e10cSrcweir {
582cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos;
583cdf0e10cSrcweir bInCluster = false;
584cdf0e10cSrcweir }
585cdf0e10cSrcweir else if( !bRightToLeft )
586cdf0e10cSrcweir {
587cdf0e10cSrcweir // left-to-right case
588cdf0e10cSrcweir if( nClusterMinPos > nCharPos )
589cdf0e10cSrcweir nClusterMinPos = nCharPos; // extend cluster
590cdf0e10cSrcweir else if( nCharPos <= nClusterMaxPos )
591cdf0e10cSrcweir /*NOTHING*/; // inside cluster
592cdf0e10cSrcweir else if( bDiacritic )
593cdf0e10cSrcweir nClusterMaxPos = nCharPos; // add diacritic to cluster
594cdf0e10cSrcweir else {
595cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
596cdf0e10cSrcweir bInCluster = false;
597cdf0e10cSrcweir }
598cdf0e10cSrcweir }
599cdf0e10cSrcweir else
600cdf0e10cSrcweir {
601cdf0e10cSrcweir // right-to-left case
602cdf0e10cSrcweir if( nClusterMaxPos < nCharPos )
603cdf0e10cSrcweir nClusterMaxPos = nCharPos; // extend cluster
604cdf0e10cSrcweir else if( nCharPos >= nClusterMinPos )
605cdf0e10cSrcweir /*NOTHING*/; // inside cluster
606cdf0e10cSrcweir else if( bDiacritic )
607cdf0e10cSrcweir {
608cdf0e10cSrcweir nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*]
609cdf0e10cSrcweir if( bClusterStart ) {
610cdf0e10cSrcweir nClusterMaxPos = nCharPos;
611cdf0e10cSrcweir bInCluster = false;
612cdf0e10cSrcweir }
613cdf0e10cSrcweir }
614cdf0e10cSrcweir else
615cdf0e10cSrcweir {
616cdf0e10cSrcweir nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster
617cdf0e10cSrcweir bInCluster = !bClusterStart;
618cdf0e10cSrcweir }
619cdf0e10cSrcweir }
620cdf0e10cSrcweir
621cdf0e10cSrcweir long nGlyphFlags = 0;
622cdf0e10cSrcweir if( bInCluster )
623cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
624cdf0e10cSrcweir if( bRightToLeft )
625cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
626cdf0e10cSrcweir if( bDiacritic )
627cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_DIACRITIC;
628cdf0e10cSrcweir
629cdf0e10cSrcweir // add resulting glyph item to layout
630e5ed4860SHerbert Dürr GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
631e5ed4860SHerbert Dürr aGI.mnNewWidth = nNewWidth;
632cdf0e10cSrcweir rLayout.AppendGlyph( aGI );
633cdf0e10cSrcweir ++nFilteredRunGlyphCount;
634cdf0e10cSrcweir nLastCharPos = nCharPos;
635cdf0e10cSrcweir bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath
636cdf0e10cSrcweir }
637cdf0e10cSrcweir aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) );
638cdf0e10cSrcweir nGlyphCount += nFilteredRunGlyphCount;
639cdf0e10cSrcweir }
640cdf0e10cSrcweir
641cdf0e10cSrcweir // sort glyphs in visual order
642cdf0e10cSrcweir // and then in logical order (e.g. diacritics after cluster start)
643cdf0e10cSrcweir rLayout.SortGlyphItems();
644cdf0e10cSrcweir
645cdf0e10cSrcweir // determine need for kashida justification
646cdf0e10cSrcweir if( (rArgs.mpDXArray || rArgs.mnLayoutWidth)
647cdf0e10cSrcweir && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) )
648cdf0e10cSrcweir rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
649cdf0e10cSrcweir
650cdf0e10cSrcweir return true;
651cdf0e10cSrcweir }
652cdf0e10cSrcweir
653cdf0e10cSrcweir #endif // ENABLE_ICU_LAYOUT
654cdf0e10cSrcweir
655cdf0e10cSrcweir // =======================================================================
656cdf0e10cSrcweir
GetLayoutEngine()657cdf0e10cSrcweir ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine()
658cdf0e10cSrcweir {
659cdf0e10cSrcweir // find best layout engine for font, platform, script and language
660cdf0e10cSrcweir #ifdef ENABLE_ICU_LAYOUT
661cdf0e10cSrcweir if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
662cdf0e10cSrcweir mpLayoutEngine = new IcuLayoutEngine( *this );
663cdf0e10cSrcweir #endif // ENABLE_ICU_LAYOUT
664cdf0e10cSrcweir
665cdf0e10cSrcweir return mpLayoutEngine;
666cdf0e10cSrcweir }
667cdf0e10cSrcweir
668cdf0e10cSrcweir // =======================================================================
669cdf0e10cSrcweir
670