| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "core/fpdfapi/fpdf_font/cpdf_font.h" | |
| 8 | |
| 9 #include <memory> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "core/fpdfapi/cpdf_modulemgr.h" | |
| 13 #include "core/fpdfapi/fpdf_font/cpdf_fontencoding.h" | |
| 14 #include "core/fpdfapi/fpdf_font/cpdf_truetypefont.h" | |
| 15 #include "core/fpdfapi/fpdf_font/cpdf_type1font.h" | |
| 16 #include "core/fpdfapi/fpdf_font/cpdf_type3font.h" | |
| 17 #include "core/fpdfapi/fpdf_font/font_int.h" | |
| 18 #include "core/fpdfapi/fpdf_page/cpdf_pagemodule.h" | |
| 19 #include "core/fpdfapi/fpdf_page/pageint.h" | |
| 20 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | |
| 21 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" | |
| 22 #include "core/fpdfapi/fpdf_parser/cpdf_document.h" | |
| 23 #include "core/fpdfapi/fpdf_parser/cpdf_name.h" | |
| 24 #include "core/fpdfapi/fpdf_parser/cpdf_stream_acc.h" | |
| 25 #include "core/fxcrt/fx_memory.h" | |
| 26 #include "core/fxge/fx_freetype.h" | |
| 27 #include "third_party/base/ptr_util.h" | |
| 28 #include "third_party/base/stl_util.h" | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 const uint8_t kChineseFontNames[][5] = {{0xCB, 0xCE, 0xCC, 0xE5, 0x00}, | |
| 33 {0xBF, 0xAC, 0xCC, 0xE5, 0x00}, | |
| 34 {0xBA, 0xDA, 0xCC, 0xE5, 0x00}, | |
| 35 {0xB7, 0xC2, 0xCB, 0xCE, 0x00}, | |
| 36 {0xD0, 0xC2, 0xCB, 0xCE, 0x00}}; | |
| 37 | |
| 38 void GetPredefinedEncoding(const CFX_ByteString& value, int* basemap) { | |
| 39 if (value == "WinAnsiEncoding") | |
| 40 *basemap = PDFFONT_ENCODING_WINANSI; | |
| 41 else if (value == "MacRomanEncoding") | |
| 42 *basemap = PDFFONT_ENCODING_MACROMAN; | |
| 43 else if (value == "MacExpertEncoding") | |
| 44 *basemap = PDFFONT_ENCODING_MACEXPERT; | |
| 45 else if (value == "PDFDocEncoding") | |
| 46 *basemap = PDFFONT_ENCODING_PDFDOC; | |
| 47 } | |
| 48 | |
| 49 } // namespace | |
| 50 | |
| 51 CPDF_Font::CPDF_Font() | |
| 52 : m_pFontFile(nullptr), | |
| 53 m_pFontDict(nullptr), | |
| 54 m_bToUnicodeLoaded(false), | |
| 55 m_Flags(0), | |
| 56 m_StemV(0), | |
| 57 m_Ascent(0), | |
| 58 m_Descent(0), | |
| 59 m_ItalicAngle(0) {} | |
| 60 | |
| 61 CPDF_Font::~CPDF_Font() { | |
| 62 if (m_pFontFile) { | |
| 63 m_pDocument->GetPageData()->ReleaseFontFileStreamAcc( | |
| 64 m_pFontFile->GetStream()->AsStream()); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 bool CPDF_Font::IsType1Font() const { | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 bool CPDF_Font::IsTrueTypeFont() const { | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 bool CPDF_Font::IsType3Font() const { | |
| 77 return false; | |
| 78 } | |
| 79 | |
| 80 bool CPDF_Font::IsCIDFont() const { | |
| 81 return false; | |
| 82 } | |
| 83 | |
| 84 const CPDF_Type1Font* CPDF_Font::AsType1Font() const { | |
| 85 return nullptr; | |
| 86 } | |
| 87 | |
| 88 CPDF_Type1Font* CPDF_Font::AsType1Font() { | |
| 89 return nullptr; | |
| 90 } | |
| 91 | |
| 92 const CPDF_TrueTypeFont* CPDF_Font::AsTrueTypeFont() const { | |
| 93 return nullptr; | |
| 94 } | |
| 95 | |
| 96 CPDF_TrueTypeFont* CPDF_Font::AsTrueTypeFont() { | |
| 97 return nullptr; | |
| 98 } | |
| 99 | |
| 100 const CPDF_Type3Font* CPDF_Font::AsType3Font() const { | |
| 101 return nullptr; | |
| 102 } | |
| 103 | |
| 104 CPDF_Type3Font* CPDF_Font::AsType3Font() { | |
| 105 return nullptr; | |
| 106 } | |
| 107 | |
| 108 const CPDF_CIDFont* CPDF_Font::AsCIDFont() const { | |
| 109 return nullptr; | |
| 110 } | |
| 111 | |
| 112 CPDF_CIDFont* CPDF_Font::AsCIDFont() { | |
| 113 return nullptr; | |
| 114 } | |
| 115 | |
| 116 bool CPDF_Font::IsUnicodeCompatible() const { | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 int CPDF_Font::CountChar(const FX_CHAR* pString, int size) const { | |
| 121 return size; | |
| 122 } | |
| 123 | |
| 124 int CPDF_Font::GetCharSize(uint32_t charcode) const { | |
| 125 return 1; | |
| 126 } | |
| 127 | |
| 128 int CPDF_Font::GlyphFromCharCodeExt(uint32_t charcode) { | |
| 129 return GlyphFromCharCode(charcode, nullptr); | |
| 130 } | |
| 131 | |
| 132 bool CPDF_Font::IsVertWriting() const { | |
| 133 const CPDF_CIDFont* pCIDFont = AsCIDFont(); | |
| 134 return pCIDFont ? pCIDFont->IsVertWriting() : m_Font.IsVertical(); | |
| 135 } | |
| 136 | |
| 137 int CPDF_Font::AppendChar(FX_CHAR* buf, uint32_t charcode) const { | |
| 138 *buf = static_cast<FX_CHAR>(charcode); | |
| 139 return 1; | |
| 140 } | |
| 141 | |
| 142 void CPDF_Font::AppendChar(CFX_ByteString& str, uint32_t charcode) const { | |
| 143 char buf[4]; | |
| 144 int len = AppendChar(buf, charcode); | |
| 145 if (len == 1) { | |
| 146 str += buf[0]; | |
| 147 } else { | |
| 148 str += CFX_ByteString(buf, len); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 CFX_WideString CPDF_Font::UnicodeFromCharCode(uint32_t charcode) const { | |
| 153 if (!m_bToUnicodeLoaded) | |
| 154 LoadUnicodeMap(); | |
| 155 | |
| 156 return m_pToUnicodeMap ? m_pToUnicodeMap->Lookup(charcode) : CFX_WideString(); | |
| 157 } | |
| 158 | |
| 159 uint32_t CPDF_Font::CharCodeFromUnicode(FX_WCHAR unicode) const { | |
| 160 if (!m_bToUnicodeLoaded) | |
| 161 LoadUnicodeMap(); | |
| 162 | |
| 163 return m_pToUnicodeMap ? m_pToUnicodeMap->ReverseLookup(unicode) : 0; | |
| 164 } | |
| 165 | |
| 166 void CPDF_Font::LoadFontDescriptor(CPDF_Dictionary* pFontDesc) { | |
| 167 m_Flags = pFontDesc->GetIntegerFor("Flags", PDFFONT_NONSYMBOLIC); | |
| 168 int ItalicAngle = 0; | |
| 169 FX_BOOL bExistItalicAngle = FALSE; | |
| 170 if (pFontDesc->KeyExist("ItalicAngle")) { | |
| 171 ItalicAngle = pFontDesc->GetIntegerFor("ItalicAngle"); | |
| 172 bExistItalicAngle = TRUE; | |
| 173 } | |
| 174 if (ItalicAngle < 0) { | |
| 175 m_Flags |= PDFFONT_ITALIC; | |
| 176 m_ItalicAngle = ItalicAngle; | |
| 177 } | |
| 178 FX_BOOL bExistStemV = FALSE; | |
| 179 if (pFontDesc->KeyExist("StemV")) { | |
| 180 m_StemV = pFontDesc->GetIntegerFor("StemV"); | |
| 181 bExistStemV = TRUE; | |
| 182 } | |
| 183 FX_BOOL bExistAscent = FALSE; | |
| 184 if (pFontDesc->KeyExist("Ascent")) { | |
| 185 m_Ascent = pFontDesc->GetIntegerFor("Ascent"); | |
| 186 bExistAscent = TRUE; | |
| 187 } | |
| 188 FX_BOOL bExistDescent = FALSE; | |
| 189 if (pFontDesc->KeyExist("Descent")) { | |
| 190 m_Descent = pFontDesc->GetIntegerFor("Descent"); | |
| 191 bExistDescent = TRUE; | |
| 192 } | |
| 193 FX_BOOL bExistCapHeight = FALSE; | |
| 194 if (pFontDesc->KeyExist("CapHeight")) { | |
| 195 bExistCapHeight = TRUE; | |
| 196 } | |
| 197 if (bExistItalicAngle && bExistAscent && bExistCapHeight && bExistDescent && | |
| 198 bExistStemV) { | |
| 199 m_Flags |= PDFFONT_USEEXTERNATTR; | |
| 200 } | |
| 201 if (m_Descent > 10) { | |
| 202 m_Descent = -m_Descent; | |
| 203 } | |
| 204 CPDF_Array* pBBox = pFontDesc->GetArrayFor("FontBBox"); | |
| 205 if (pBBox) { | |
| 206 m_FontBBox.left = pBBox->GetIntegerAt(0); | |
| 207 m_FontBBox.bottom = pBBox->GetIntegerAt(1); | |
| 208 m_FontBBox.right = pBBox->GetIntegerAt(2); | |
| 209 m_FontBBox.top = pBBox->GetIntegerAt(3); | |
| 210 } | |
| 211 | |
| 212 CPDF_Stream* pFontFile = pFontDesc->GetStreamFor("FontFile"); | |
| 213 if (!pFontFile) | |
| 214 pFontFile = pFontDesc->GetStreamFor("FontFile2"); | |
| 215 if (!pFontFile) | |
| 216 pFontFile = pFontDesc->GetStreamFor("FontFile3"); | |
| 217 if (!pFontFile) | |
| 218 return; | |
| 219 | |
| 220 m_pFontFile = m_pDocument->LoadFontFile(pFontFile); | |
| 221 if (!m_pFontFile) | |
| 222 return; | |
| 223 | |
| 224 const uint8_t* pFontData = m_pFontFile->GetData(); | |
| 225 uint32_t dwFontSize = m_pFontFile->GetSize(); | |
| 226 if (!m_Font.LoadEmbedded(pFontData, dwFontSize)) { | |
| 227 m_pDocument->GetPageData()->ReleaseFontFileStreamAcc( | |
| 228 m_pFontFile->GetStream()->AsStream()); | |
| 229 m_pFontFile = nullptr; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 void CPDF_Font::CheckFontMetrics() { | |
| 234 if (m_FontBBox.top == 0 && m_FontBBox.bottom == 0 && m_FontBBox.left == 0 && | |
| 235 m_FontBBox.right == 0) { | |
| 236 FXFT_Face face = m_Font.GetFace(); | |
| 237 if (face) { | |
| 238 m_FontBBox.left = TT2PDF(FXFT_Get_Face_xMin(face), face); | |
| 239 m_FontBBox.bottom = TT2PDF(FXFT_Get_Face_yMin(face), face); | |
| 240 m_FontBBox.right = TT2PDF(FXFT_Get_Face_xMax(face), face); | |
| 241 m_FontBBox.top = TT2PDF(FXFT_Get_Face_yMax(face), face); | |
| 242 m_Ascent = TT2PDF(FXFT_Get_Face_Ascender(face), face); | |
| 243 m_Descent = TT2PDF(FXFT_Get_Face_Descender(face), face); | |
| 244 } else { | |
| 245 FX_BOOL bFirst = TRUE; | |
| 246 for (int i = 0; i < 256; i++) { | |
| 247 FX_RECT rect = GetCharBBox(i); | |
| 248 if (rect.left == rect.right) { | |
| 249 continue; | |
| 250 } | |
| 251 if (bFirst) { | |
| 252 m_FontBBox = rect; | |
| 253 bFirst = FALSE; | |
| 254 } else { | |
| 255 if (m_FontBBox.top < rect.top) { | |
| 256 m_FontBBox.top = rect.top; | |
| 257 } | |
| 258 if (m_FontBBox.right < rect.right) { | |
| 259 m_FontBBox.right = rect.right; | |
| 260 } | |
| 261 if (m_FontBBox.left > rect.left) { | |
| 262 m_FontBBox.left = rect.left; | |
| 263 } | |
| 264 if (m_FontBBox.bottom > rect.bottom) { | |
| 265 m_FontBBox.bottom = rect.bottom; | |
| 266 } | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 } | |
| 271 if (m_Ascent == 0 && m_Descent == 0) { | |
| 272 FX_RECT rect = GetCharBBox('A'); | |
| 273 m_Ascent = rect.bottom == rect.top ? m_FontBBox.top : rect.top; | |
| 274 rect = GetCharBBox('g'); | |
| 275 m_Descent = rect.bottom == rect.top ? m_FontBBox.bottom : rect.bottom; | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 void CPDF_Font::LoadUnicodeMap() const { | |
| 280 m_bToUnicodeLoaded = true; | |
| 281 CPDF_Stream* pStream = m_pFontDict->GetStreamFor("ToUnicode"); | |
| 282 if (!pStream) { | |
| 283 return; | |
| 284 } | |
| 285 m_pToUnicodeMap.reset(new CPDF_ToUnicodeMap); | |
| 286 m_pToUnicodeMap->Load(pStream); | |
| 287 } | |
| 288 | |
| 289 int CPDF_Font::GetStringWidth(const FX_CHAR* pString, int size) { | |
| 290 int offset = 0; | |
| 291 int width = 0; | |
| 292 while (offset < size) { | |
| 293 uint32_t charcode = GetNextChar(pString, size, offset); | |
| 294 width += GetCharWidthF(charcode); | |
| 295 } | |
| 296 return width; | |
| 297 } | |
| 298 | |
| 299 CPDF_Font* CPDF_Font::GetStockFont(CPDF_Document* pDoc, | |
| 300 const CFX_ByteStringC& name) { | |
| 301 CFX_ByteString fontname(name); | |
| 302 int font_id = PDF_GetStandardFontName(&fontname); | |
| 303 if (font_id < 0) | |
| 304 return nullptr; | |
| 305 | |
| 306 CPDF_FontGlobals* pFontGlobals = | |
| 307 CPDF_ModuleMgr::Get()->GetPageModule()->GetFontGlobals(); | |
| 308 CPDF_Font* pFont = pFontGlobals->Find(pDoc, font_id); | |
| 309 if (pFont) | |
| 310 return pFont; | |
| 311 | |
| 312 CPDF_Dictionary* pDict = new CPDF_Dictionary(pDoc->GetByteStringPool()); | |
| 313 pDict->SetNameFor("Type", "Font"); | |
| 314 pDict->SetNameFor("Subtype", "Type1"); | |
| 315 pDict->SetNameFor("BaseFont", fontname); | |
| 316 pDict->SetNameFor("Encoding", "WinAnsiEncoding"); | |
| 317 return pFontGlobals->Set(pDoc, font_id, CPDF_Font::Create(nullptr, pDict)); | |
| 318 } | |
| 319 | |
| 320 std::unique_ptr<CPDF_Font> CPDF_Font::Create(CPDF_Document* pDoc, | |
| 321 CPDF_Dictionary* pFontDict) { | |
| 322 CFX_ByteString type = pFontDict->GetStringFor("Subtype"); | |
| 323 std::unique_ptr<CPDF_Font> pFont; | |
| 324 if (type == "TrueType") { | |
| 325 CFX_ByteString tag = pFontDict->GetStringFor("BaseFont").Left(4); | |
| 326 for (size_t i = 0; i < FX_ArraySize(kChineseFontNames); ++i) { | |
| 327 if (tag == CFX_ByteString(kChineseFontNames[i], 4)) { | |
| 328 CPDF_Dictionary* pFontDesc = pFontDict->GetDictFor("FontDescriptor"); | |
| 329 if (!pFontDesc || !pFontDesc->KeyExist("FontFile2")) | |
| 330 pFont.reset(new CPDF_CIDFont); | |
| 331 break; | |
| 332 } | |
| 333 } | |
| 334 if (!pFont) | |
| 335 pFont.reset(new CPDF_TrueTypeFont); | |
| 336 } else if (type == "Type3") { | |
| 337 pFont.reset(new CPDF_Type3Font); | |
| 338 } else if (type == "Type0") { | |
| 339 pFont.reset(new CPDF_CIDFont); | |
| 340 } else { | |
| 341 pFont.reset(new CPDF_Type1Font); | |
| 342 } | |
| 343 pFont->m_pFontDict = pFontDict; | |
| 344 pFont->m_pDocument = pDoc; | |
| 345 pFont->m_BaseFont = pFontDict->GetStringFor("BaseFont"); | |
| 346 return pFont->Load() ? std::move(pFont) : std::unique_ptr<CPDF_Font>(); | |
| 347 } | |
| 348 | |
| 349 uint32_t CPDF_Font::GetNextChar(const FX_CHAR* pString, | |
| 350 int nStrLen, | |
| 351 int& offset) const { | |
| 352 if (offset < 0 || nStrLen < 1) { | |
| 353 return 0; | |
| 354 } | |
| 355 uint8_t ch = offset < nStrLen ? pString[offset++] : pString[nStrLen - 1]; | |
| 356 return static_cast<uint32_t>(ch); | |
| 357 } | |
| 358 | |
| 359 void CPDF_Font::LoadPDFEncoding(CPDF_Object* pEncoding, | |
| 360 int& iBaseEncoding, | |
| 361 std::vector<CFX_ByteString>* pCharNames, | |
| 362 bool bEmbedded, | |
| 363 bool bTrueType) { | |
| 364 if (!pEncoding) { | |
| 365 if (m_BaseFont == "Symbol") { | |
| 366 iBaseEncoding = bTrueType ? PDFFONT_ENCODING_MS_SYMBOL | |
| 367 : PDFFONT_ENCODING_ADOBE_SYMBOL; | |
| 368 } else if (!bEmbedded && iBaseEncoding == PDFFONT_ENCODING_BUILTIN) { | |
| 369 iBaseEncoding = PDFFONT_ENCODING_WINANSI; | |
| 370 } | |
| 371 return; | |
| 372 } | |
| 373 if (pEncoding->IsName()) { | |
| 374 if (iBaseEncoding == PDFFONT_ENCODING_ADOBE_SYMBOL || | |
| 375 iBaseEncoding == PDFFONT_ENCODING_ZAPFDINGBATS) { | |
| 376 return; | |
| 377 } | |
| 378 if ((m_Flags & PDFFONT_SYMBOLIC) && m_BaseFont == "Symbol") { | |
| 379 if (!bTrueType) { | |
| 380 iBaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL; | |
| 381 } | |
| 382 return; | |
| 383 } | |
| 384 CFX_ByteString bsEncoding = pEncoding->GetString(); | |
| 385 if (bsEncoding.Compare("MacExpertEncoding") == 0) { | |
| 386 bsEncoding = "WinAnsiEncoding"; | |
| 387 } | |
| 388 GetPredefinedEncoding(bsEncoding, &iBaseEncoding); | |
| 389 return; | |
| 390 } | |
| 391 | |
| 392 CPDF_Dictionary* pDict = pEncoding->AsDictionary(); | |
| 393 if (!pDict) | |
| 394 return; | |
| 395 | |
| 396 if (iBaseEncoding != PDFFONT_ENCODING_ADOBE_SYMBOL && | |
| 397 iBaseEncoding != PDFFONT_ENCODING_ZAPFDINGBATS) { | |
| 398 CFX_ByteString bsEncoding = pDict->GetStringFor("BaseEncoding"); | |
| 399 if (bsEncoding.Compare("MacExpertEncoding") == 0 && bTrueType) { | |
| 400 bsEncoding = "WinAnsiEncoding"; | |
| 401 } | |
| 402 GetPredefinedEncoding(bsEncoding, &iBaseEncoding); | |
| 403 } | |
| 404 if ((!bEmbedded || bTrueType) && iBaseEncoding == PDFFONT_ENCODING_BUILTIN) | |
| 405 iBaseEncoding = PDFFONT_ENCODING_STANDARD; | |
| 406 | |
| 407 CPDF_Array* pDiffs = pDict->GetArrayFor("Differences"); | |
| 408 if (!pDiffs) | |
| 409 return; | |
| 410 | |
| 411 pCharNames->resize(256); | |
| 412 uint32_t cur_code = 0; | |
| 413 for (uint32_t i = 0; i < pDiffs->GetCount(); i++) { | |
| 414 CPDF_Object* pElement = pDiffs->GetDirectObjectAt(i); | |
| 415 if (!pElement) | |
| 416 continue; | |
| 417 | |
| 418 if (CPDF_Name* pName = pElement->AsName()) { | |
| 419 if (cur_code < 256) | |
| 420 (*pCharNames)[cur_code] = pName->GetString(); | |
| 421 cur_code++; | |
| 422 } else { | |
| 423 cur_code = pElement->GetInteger(); | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 bool CPDF_Font::IsStandardFont() const { | |
| 429 if (!IsType1Font()) | |
| 430 return false; | |
| 431 if (m_pFontFile) | |
| 432 return false; | |
| 433 if (AsType1Font()->GetBase14Font() < 0) | |
| 434 return false; | |
| 435 return true; | |
| 436 } | |
| 437 | |
| 438 const FX_CHAR* CPDF_Font::GetAdobeCharName( | |
| 439 int iBaseEncoding, | |
| 440 const std::vector<CFX_ByteString>& charnames, | |
| 441 int charcode) { | |
| 442 if (charcode < 0 || charcode >= 256) { | |
| 443 ASSERT(false); | |
| 444 return nullptr; | |
| 445 } | |
| 446 | |
| 447 if (!charnames.empty() && !charnames[charcode].IsEmpty()) | |
| 448 return charnames[charcode].c_str(); | |
| 449 | |
| 450 const FX_CHAR* name = nullptr; | |
| 451 if (iBaseEncoding) | |
| 452 name = PDF_CharNameFromPredefinedCharSet(iBaseEncoding, charcode); | |
| 453 return name && name[0] ? name : nullptr; | |
| 454 } | |
| 455 | |
| 456 uint32_t CPDF_Font::FallbackFontFromCharcode(uint32_t charcode) { | |
| 457 if (m_FontFallbacks.empty()) { | |
| 458 m_FontFallbacks.push_back(pdfium::MakeUnique<CFX_Font>()); | |
| 459 m_FontFallbacks[0]->LoadSubst("Arial", IsTrueTypeFont(), m_Flags, | |
| 460 m_StemV * 5, m_ItalicAngle, 0, | |
| 461 IsVertWriting()); | |
| 462 } | |
| 463 return 0; | |
| 464 } | |
| 465 | |
| 466 int CPDF_Font::FallbackGlyphFromCharcode(int fallbackFont, uint32_t charcode) { | |
| 467 if (fallbackFont < 0 || | |
| 468 fallbackFont >= pdfium::CollectionSize<int>(m_FontFallbacks)) { | |
| 469 return -1; | |
| 470 } | |
| 471 int glyph = | |
| 472 FXFT_Get_Char_Index(m_FontFallbacks[fallbackFont]->GetFace(), charcode); | |
| 473 if (glyph == 0 || glyph == 0xffff) | |
| 474 return -1; | |
| 475 return glyph; | |
| 476 } | |
| OLD | NEW |