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