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