xref: /aoo41x/main/vcl/source/glyphs/gcach_layout.cxx (revision 248a599f)
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