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