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