1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // Description: Implements the Graphite interfaces with access to the
29 //              platform's font and graphics systems.
30 
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 
34 // We need this to enable namespace support in libgrengine headers.
35 #define GR_NAMESPACE
36 
37 // Header files
38 //
39 // Standard Library
40 #include <string>
41 #include <cassert>
42 // Libraries
43 #include <rtl/string.hxx>
44 #include <rtl/ustring.hxx>
45 #include <i18npool/mslangid.hxx>
46 // Platform
47 #ifndef WNT
48 #include <unx/saldisp.hxx>
49 
50 #include <salgdi.hxx>
51 
52 #include <freetype/ftsynth.h>
53 
54 // Module
55 #include "gcach_ftyp.hxx"
56 
57 #include <graphite_features.hxx>
58 #include <graphite_adaptors.hxx>
59 
60 // Module private type definitions and forward declarations.
61 //
62 using gr::GrResult;
63 namespace
64 {
65     inline float from_hinted(const int x) {
66         return static_cast<float>(x + 32) / 64.0;
67     }
68     typedef std::hash_map<long,bool> SilfMap;
69     SilfMap sSilfMap;
70 }
71 extern FT_Error (*pFTEmbolden)(FT_GlyphSlot);
72 extern FT_Error (*pFTOblique)(FT_GlyphSlot);
73 
74 // class CharacterRenderProperties implentation.
75 //
76 FontProperties::FontProperties(const FreetypeServerFont &font) throw()
77 {
78     clrFore = gr::kclrBlack;
79     clrBack = gr::kclrTransparent;
80 
81     pixHeight = from_hinted(font.GetMetricsFT().height);
82 
83     switch (font.GetFontSelData().meWeight)
84     {
85         case WEIGHT_SEMIBOLD: case WEIGHT_BOLD:
86         case WEIGHT_ULTRABOLD: case WEIGHT_BLACK:
87             fBold = true;
88             break;
89         default :
90             fBold = false;
91     }
92 
93     switch (font.GetFontSelData().meItalic)
94     {
95         case ITALIC_NORMAL: case ITALIC_OBLIQUE:
96             fItalic = true;
97             break;
98         default :
99             fItalic = false;
100     }
101 
102     // Get the font name, but prefix with file name hash in case
103     // there are 2 fonts on the system with the same face name
104     sal_Int32 nHashCode = font.GetFontFileName()->hashCode();
105     ::rtl::OUStringBuffer nHashFaceName;
106     nHashFaceName.append(nHashCode, 16);
107     const sal_Unicode    * name = font.GetFontSelData().maName.GetBuffer();
108     nHashFaceName.append(name);
109 
110     const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1,
111                     static_cast<size_t>(nHashFaceName.getLength()));
112 
113     std::copy(nHashFaceName.getStr(), nHashFaceName.getStr() + name_sz, szFaceName);
114     szFaceName[name_sz] = '\0';
115 }
116 
117 // class GraphiteFontAdaptor implementaion.
118 //
119 GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpiX, const sal_Int32 dpiY)
120   :    mrFont(static_cast<FreetypeServerFont &>(sfont)),
121     maFontProperties(static_cast<FreetypeServerFont &>(sfont)),
122     mnDpiX(dpiX),
123     mnDpiY(dpiY),
124     mfAscent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().ascender)),
125     mfDescent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().descender)),
126     mfEmUnits(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().y_ppem),
127     mpFeatures(NULL)
128 {
129     const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage );
130     rtl::OString name = rtl::OUStringToOString(
131         sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 );
132 #ifdef DEBUG
133     printf("GraphiteFontAdaptor %lx %s italic=%u bold=%u\n", (long)this, name.getStr(),
134            maFontProperties.fItalic, maFontProperties.fBold);
135 #endif
136     sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
137     if (nFeat > 0)
138     {
139         rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
140         mpFeatures = new grutils::GrFeatureParser(*this, aFeat.getStr(), aLang.getStr());
141 #ifdef DEBUG
142         printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n",
143             rtl::OUStringToOString( sfont.GetFontSelData().maName,
144             RTL_TEXTENCODING_UTF8 ).getStr(),
145             rtl::OUStringToOString( sfont.GetFontSelData().maTargetName,
146             RTL_TEXTENCODING_UTF8 ).getStr(),
147             rtl::OUStringToOString( sfont.GetFontSelData().maSearchName,
148             RTL_TEXTENCODING_UTF8 ).getStr(),
149             sfont.GetFontSelData().meLanguage,
150             (int)mpFeatures->getFontFeatures(NULL), mpFeatures->parseErrors());
151 #endif
152     }
153     else
154     {
155         mpFeatures = new grutils::GrFeatureParser(*this, aLang.getStr());
156     }
157 }
158 
159 GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor &rhs) throw()
160  :    Font(rhs),
161      mrFont (rhs.mrFont), maFontProperties(rhs.maFontProperties),
162     mnDpiX(rhs.mnDpiX), mnDpiY(rhs.mnDpiY),
163     mfAscent(rhs.mfAscent), mfDescent(rhs.mfDescent), mfEmUnits(rhs.mfEmUnits),
164     mpFeatures(NULL)
165 {
166     if (rhs.mpFeatures) mpFeatures = new grutils::GrFeatureParser(*(rhs.mpFeatures));
167 }
168 
169 
170 GraphiteFontAdaptor::~GraphiteFontAdaptor() throw()
171 {
172     maGlyphMetricMap.clear();
173     if (mpFeatures) delete mpFeatures;
174     mpFeatures = NULL;
175 }
176 
177 void GraphiteFontAdaptor::UniqueCacheInfo(ext_std::wstring & face_name_out, bool & bold_out, bool & italic_out)
178 {
179     face_name_out = maFontProperties.szFaceName;
180     bold_out = maFontProperties.fBold;
181     italic_out = maFontProperties.fItalic;
182 }
183 
184 bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont & font) throw()
185 {
186     // NOTE: this assumes that the same FTFace pointer won't be reused,
187     // so FtFontInfo::ReleaseFaceFT must only be called at shutdown.
188     FreetypeServerFont & aFtFont = dynamic_cast<FreetypeServerFont &>(font);
189     FT_Face aFace = reinterpret_cast<FT_FaceRec_*>(aFtFont.GetFtFace());
190     SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFace));
191     if (i != sSilfMap.end())
192     {
193 #ifdef DEBUG
194         if (static_cast<bool>(aFtFont.GetTable("Silf", 0)) != (*i).second)
195             printf("Silf cache font mismatch\n");
196 #endif
197         return (*i).second;
198     }
199     bool bHasSilf = aFtFont.GetTable("Silf", 0);
200     sSilfMap[reinterpret_cast<long>(aFace)] = bHasSilf;
201     return bHasSilf;
202 }
203 
204 
205 gr::Font * GraphiteFontAdaptor::copyThis() {
206     return new GraphiteFontAdaptor(*this);
207 }
208 
209 
210 unsigned int GraphiteFontAdaptor::getDPIx() {
211     return mnDpiX;
212 }
213 
214 
215 unsigned int GraphiteFontAdaptor::getDPIy() {
216     return mnDpiY;
217 }
218 
219 
220 float GraphiteFontAdaptor::ascent() {
221     return mfAscent;
222 }
223 
224 
225 float GraphiteFontAdaptor::descent() {
226     return mfDescent;
227 }
228 
229 
230 bool GraphiteFontAdaptor::bold() {
231     return maFontProperties.fBold;
232 }
233 
234 
235 bool GraphiteFontAdaptor::italic() {
236     return maFontProperties.fItalic;
237 }
238 
239 
240 float GraphiteFontAdaptor::height() {
241     return maFontProperties.pixHeight;
242 }
243 
244 
245 void GraphiteFontAdaptor::getFontMetrics(float * ascent_out, float * descent_out, float * em_square_out) {
246     if (ascent_out)        *ascent_out    = mfAscent;
247     if (descent_out)    *descent_out   = mfDescent;
248     if (em_square_out)    *em_square_out = mfEmUnits;
249 }
250 
251 
252 const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * buffer_sz)
253 {
254     char tag_name[5] = {char(table_id >> 24), char(table_id >> 16), char(table_id >> 8), char(table_id), 0};
255     sal_uLong temp = *buffer_sz;
256 
257     const void * const tbl_buf = static_cast<FreetypeServerFont &>(mrFont).GetTable(tag_name, &temp);
258     *buffer_sz = temp;
259 
260     return tbl_buf;
261 }
262 
263 #define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
264 
265 // Return the glyph's metrics in pixels.
266 void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances)
267 {
268     // There used to be problems when orientation was set however, this no
269     // longer seems to be the case and the Glyph Metric cache in
270     // FreetypeServerFont is more efficient since it lasts between calls to VCL
271 #if 1
272     const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId);
273 
274     aBounding.right  = aBounding.left = metric.GetOffset().X();
275     aBounding.bottom = aBounding.top  = -metric.GetOffset().Y();
276     aBounding.right  += metric.GetSize().Width();
277     aBounding.bottom -= metric.GetSize().Height();
278 
279     advances.x = metric.GetDelta().X();
280     advances.y = -metric.GetDelta().Y();
281 
282 #else
283     // The problem with the code below is that the cache only lasts
284     // as long as the life time of the GraphiteFontAdaptor, which
285     // is created once per call to X11SalGraphics::GetTextLayout
286     GlyphMetricMap::const_iterator gm_itr = maGlyphMetricMap.find(nGlyphId);
287     if (gm_itr != maGlyphMetricMap.end())
288     {
289         // We've cached the results from last time.
290         aBounding = gm_itr->second.first;
291         advances    = gm_itr->second.second;
292     }
293     else
294     {
295         // We need to look up the glyph.
296         FT_Int nLoadFlags = mrFont.GetLoadFlags();
297 
298         FT_Face aFace = reinterpret_cast<FT_Face>(mrFont.GetFtFace());
299         if (!aFace)
300         {
301             aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
302             advances.x = advances.y = 0;
303             return;
304         }
305         FT_Error aStatus = -1;
306         aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags);
307         if( aStatus != FT_Err_Ok || (!aFace->glyph))
308         {
309             aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
310             advances.x = advances.y = 0;
311             return;
312         }
313         // check whether we need synthetic bold/italic otherwise metric is wrong
314         if (mrFont.NeedsArtificialBold() && pFTEmbolden)
315             (*pFTEmbolden)(aFace->glyph);
316 
317         if (mrFont.NeedsArtificialItalic() && pFTOblique)
318             (*pFTOblique)(aFace->glyph);
319 
320         const FT_Glyph_Metrics &gm = aFace->glyph->metrics;
321 
322         // Fill out the bounding box an advances.
323         aBounding.top = aBounding.bottom = fix26_6(gm.horiBearingY);
324         aBounding.bottom -= fix26_6(gm.height);
325         aBounding.left = aBounding.right = fix26_6(gm.horiBearingX);
326         aBounding.right += fix26_6(gm.width);
327         advances.x = fix26_6(gm.horiAdvance);
328         advances.y = 0;
329 
330         // Now add an entry to our metrics map.
331         maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances);
332     }
333 #endif
334 }
335 
336 #endif
337