/* ============================== idFont::GetScaledGlyph ============================== */ void idFont::GetScaledGlyph( float scale, uint32 idx, scaledGlyphInfo_t& glyphInfo ) const { if( alias != NULL ) { return alias->GetScaledGlyph( scale, idx, glyphInfo ); } if( fontInfo != NULL ) { int i = GetGlyphIndex( idx ); const int asterisk = 42; if( i == -1 && idx != asterisk ) { i = GetGlyphIndex( asterisk ); } if( i >= 0 ) { float invMaterialWidth = 1.0f / fontInfo->material->GetImageWidth(); float invMaterialHeight = 1.0f / fontInfo->material->GetImageHeight(); glyphInfo_t& gi = fontInfo->glyphData[i]; glyphInfo.xSkip = scale * gi.xSkip; glyphInfo.top = scale * gi.top; glyphInfo.left = scale * gi.left; glyphInfo.width = scale * gi.width; glyphInfo.height = scale * gi.height; glyphInfo.s1 = ( gi.s - 0.5f ) * invMaterialWidth; glyphInfo.t1 = ( gi.t - 0.5f ) * invMaterialHeight; glyphInfo.s2 = ( gi.s + gi.width + 0.5f ) * invMaterialWidth; glyphInfo.t2 = ( gi.t + gi.height + 0.5f ) * invMaterialHeight; glyphInfo.material = fontInfo->material; return; } } memset( &glyphInfo, 0, sizeof( glyphInfo ) ); }
FX_BOOL CFX_GEFont::GetCharWidth(FX_WCHAR wUnicode, int32_t& iWidth, FX_BOOL bRecursive, FX_BOOL bCharCode) { FXSYS_assert(m_pCharWidthMap != NULL); iWidth = m_pCharWidthMap->GetAt(wUnicode, 0); if (iWidth < 1) { if (!m_pProvider || !m_pProvider->GetCharWidth(this, wUnicode, iWidth, bCharCode)) { IFX_Font* pFont = NULL; int32_t iGlyph = GetGlyphIndex(wUnicode, TRUE, &pFont, bCharCode); if (iGlyph != 0xFFFF && pFont != NULL) { if (pFont == (IFX_Font*)this) { iWidth = m_pFont->GetGlyphWidth(iGlyph); if (iWidth < 0) { iWidth = -1; } } else if (((CFX_GEFont*)pFont) ->GetCharWidth(wUnicode, iWidth, FALSE, bCharCode)) { return TRUE; } } else { iWidth = -1; } } Lock(); m_pCharWidthMap->SetAtGrow(wUnicode, (int16_t)iWidth); Unlock(); } else if (iWidth == 65535) { iWidth = -1; } return iWidth > 0; }
FX_BOOL CFX_GEFont::GetCharBBox(FX_WCHAR wUnicode, CFX_Rect& bbox, FX_BOOL bRecursive, FX_BOOL bCharCode) { FXSYS_assert(m_pRectArray != NULL); FXSYS_assert(m_pBBoxMap != NULL); void* pRect = NULL; if (!m_pBBoxMap->Lookup((void*)(uintptr_t)wUnicode, pRect)) { IFX_Font* pFont = NULL; int32_t iGlyph = GetGlyphIndex(wUnicode, TRUE, &pFont, bCharCode); if (iGlyph != 0xFFFF && pFont != NULL) { if (pFont == (IFX_Font*)this) { FX_RECT rtBBox; if (m_pFont->GetGlyphBBox(iGlyph, rtBBox)) { Lock(); CFX_Rect rt; rt.Set(rtBBox.left, rtBBox.top, rtBBox.Width(), rtBBox.Height()); int32_t index = m_pRectArray->Add(rt); pRect = m_pRectArray->GetPtrAt(index); m_pBBoxMap->SetAt((void*)(uintptr_t)wUnicode, pRect); Unlock(); } } else if (((CFX_GEFont*)pFont) ->GetCharBBox(wUnicode, bbox, FALSE, bCharCode)) { return TRUE; } } } if (pRect == NULL) { return FALSE; } bbox = *(FX_LPCRECT)pRect; return TRUE; }
FX_BOOL CFGAS_GEFont::GetCharBBoxInternal(FX_WCHAR wUnicode, CFX_Rect& bbox, FX_BOOL bRecursive, FX_BOOL bCharCode) { ASSERT(m_pRectArray); ASSERT(m_pBBoxMap); void* pRect = nullptr; if (!m_pBBoxMap->Lookup((void*)(uintptr_t)wUnicode, pRect)) { CFGAS_GEFont* pFont = nullptr; int32_t iGlyph = GetGlyphIndex(wUnicode, TRUE, &pFont, bCharCode); if (iGlyph != 0xFFFF && pFont) { if (pFont == this) { FX_RECT rtBBox; if (m_pFont->GetGlyphBBox(iGlyph, rtBBox)) { CFX_Rect rt; rt.Set(rtBBox.left, rtBBox.top, rtBBox.Width(), rtBBox.Height()); int32_t index = m_pRectArray->Add(rt); pRect = m_pRectArray->GetPtrAt(index); m_pBBoxMap->SetAt((void*)(uintptr_t)wUnicode, pRect); } } else if (pFont->GetCharBBoxInternal(wUnicode, bbox, FALSE, bCharCode)) { return TRUE; } } } if (!pRect) return FALSE; bbox = *static_cast<const CFX_Rect*>(pRect); return TRUE; }
FX_BOOL CFGAS_GEFont::GetCharWidthInternal(FX_WCHAR wUnicode, int32_t& iWidth, FX_BOOL bRecursive, FX_BOOL bCharCode) { ASSERT(m_pCharWidthMap); iWidth = m_pCharWidthMap->GetAt(wUnicode, 0); if (iWidth < 1) { if (!m_pProvider || !m_pProvider->GetCharWidth(this, wUnicode, iWidth, bCharCode)) { CFGAS_GEFont* pFont = nullptr; int32_t iGlyph = GetGlyphIndex(wUnicode, TRUE, &pFont, bCharCode); if (iGlyph != 0xFFFF && pFont) { if (pFont == this) { iWidth = m_pFont->GetGlyphWidth(iGlyph); if (iWidth < 0) { iWidth = -1; } } else if (pFont->GetCharWidthInternal(wUnicode, iWidth, FALSE, bCharCode)) { return TRUE; } } else { iWidth = -1; } } m_pCharWidthMap->SetAtGrow(wUnicode, (int16_t)iWidth); } else if (iWidth == 65535) { iWidth = -1; } return iWidth > 0; }
/* ============================== idFont::GetGlyphWidth ============================== */ float idFont::GetGlyphWidth( float scale, uint32 idx ) const { if ( alias != NULL ) { return alias->GetGlyphWidth( scale, idx ); } if ( fontInfo != NULL ) { int i = GetGlyphIndex( idx ); const int asterisk = 42; if ( i == -1 && idx != asterisk ) { i = GetGlyphIndex( asterisk ); } if ( i >= 0 ) { return scale * fontInfo->glyphData[i].xSkip; } } return 0.0f; }
bool TrueTypeTileset::Provides(char32_t code) { char32_t relative_code = (code & Tileset::kCharOffsetMask); if (Tileset::IsFontOffset(m_offset)) { // TrueType fonts do not provide Box Drawing and Block Elements characters by default. if ((relative_code >= 0x2500 && relative_code <= 0x257F && !m_use_box_drawing) || (relative_code >= 0x2580 && relative_code <= 0x259F && !m_use_block_elements)) { return false; } } return GetGlyphIndex(code) > 0; }
std::shared_ptr<TileInfo> TrueTypeTileset::Get(char32_t code) { if (auto cached = Tileset::Get(code)) return cached; FT_UInt index = GetGlyphIndex(code); if (index == 0) throw std::runtime_error("TrueTypeTileset: request for a tile that is not provided by the tileset"); if (FT_Load_Glyph(*m_font_face, index, m_hinting)) throw std::runtime_error("TrueTypeTileset: can't load character glyph"); if ((*m_font_face)->glyph->format != FT_GLYPH_FORMAT_BITMAP) { FT_Render_Mode render_mode = m_render_mode; if (FT_Render_Glyph((*m_font_face)->glyph, render_mode) != 0) { throw std::runtime_error("TrueTypeTileset: can't render glyph"); } } FT_GlyphSlot& slot = (*m_font_face)->glyph; int rows = slot->bitmap.rows; int columns = 0; int pixel_size = 0; int height = (*m_font_face)->size->metrics.height >> 6; int descender = (*m_font_face)->size->metrics.descender >> 6; int bx = (slot->metrics.horiBearingX >> 6) / 64; int by = slot->metrics.horiBearingY >> 6; if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { columns = slot->bitmap.width; pixel_size = 1; } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { columns = slot->bitmap.width/3; pixel_size = 3; } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { columns = slot->bitmap.width; pixel_size = 0; } Bitmap glyph(Size(columns, rows), Color(0, 0, 0, 0)); for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { uint8_t* p = slot->bitmap.buffer + y*slot->bitmap.pitch + x*pixel_size; if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { Color c(p[0], 255, 255, 255); glyph(x, y) = c; } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { Color c(255, p[0], p[1], p[2]); glyph(x, y) = c; } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { int j = x%8; int i = (x-j)/8; uint8_t byte = *(slot->bitmap.buffer + y*slot->bitmap.pitch + i); uint8_t alpha = (byte & (1 << (7-j)))? 255: 0; glyph(x, y) = Color(alpha, 255, 255, 255); } } } int descender2 = (*m_font_face)->size->metrics.descender >> 6; float wff = slot->metrics.horiAdvance / 4096.0f; float hff = (*m_font_face)->size->metrics.height / 64.0f; int dy = -((by-descender2) - hff/2); Point offset; if (m_alignment == TileAlignment::Center) { int dx = -std::round((wff + 0.5f) / 2.0f) + bx; offset = Point(dx, dy); } else if (m_alignment == TileAlignment::DeadCenter) { Point center = glyph.CenterOfMass(); offset = Point(-center.x, -center.y); } else { if (m_monospace) offset = Point(bx, m_tile_size.height/2+dy); else offset = Point(m_tile_size.width/2-(columns+bx)/2, m_tile_size.height/2+dy); } auto tile = std::make_shared<TileInfo>(); tile->tileset = this; tile->bitmap = glyph; tile->offset = offset; tile->alignment = m_alignment; tile->spacing = m_spacing; m_cache[code] = tile; return tile; }
int32_t CFX_GEFont::GetGlyphIndex(FX_WCHAR wUnicode, FX_BOOL bCharCode) { return GetGlyphIndex(wUnicode, TRUE, NULL, bCharCode); }
int CPDF_CIDFont::GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) { if (pVertGlyph) *pVertGlyph = false; if (!m_pFontFile && !m_pStreamAcc) { uint16_t cid = CIDFromCharCode(charcode); FX_WCHAR unicode = 0; if (m_bCIDIsGID) { #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ return cid; #else if (m_Flags & FXFONT_SYMBOLIC) return cid; CFX_WideString uni_str = UnicodeFromCharCode(charcode); if (uni_str.IsEmpty()) return cid; unicode = uni_str.GetAt(0); #endif } else { if (cid && m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded()) unicode = m_pCID2UnicodeMap->UnicodeFromCID(cid); if (unicode == 0) unicode = GetUnicodeFromCharCode(charcode); if (unicode == 0) { CFX_WideString unicode_str = UnicodeFromCharCode(charcode); if (!unicode_str.IsEmpty()) unicode = unicode_str.GetAt(0); } } FXFT_Face face = m_Font.GetFace(); if (unicode == 0) { if (!m_bAdobeCourierStd) return charcode ? static_cast<int>(charcode) : -1; charcode += 31; bool bMSUnicode = FT_UseTTCharmap(face, 3, 1); bool bMacRoman = !bMSUnicode && FT_UseTTCharmap(face, 1, 0); int iBaseEncoding = PDFFONT_ENCODING_STANDARD; if (bMSUnicode) iBaseEncoding = PDFFONT_ENCODING_WINANSI; else if (bMacRoman) iBaseEncoding = PDFFONT_ENCODING_MACROMAN; const FX_CHAR* name = GetAdobeCharName( iBaseEncoding, std::vector<CFX_ByteString>(), charcode); if (!name) return charcode ? static_cast<int>(charcode) : -1; int index = 0; uint16_t name_unicode = PDF_UnicodeFromAdobeName(name); if (!name_unicode) return charcode ? static_cast<int>(charcode) : -1; if (iBaseEncoding == PDFFONT_ENCODING_STANDARD) return FXFT_Get_Char_Index(face, name_unicode); if (iBaseEncoding == PDFFONT_ENCODING_WINANSI) { index = FXFT_Get_Char_Index(face, name_unicode); } else { ASSERT(iBaseEncoding == PDFFONT_ENCODING_MACROMAN); uint32_t maccode = FT_CharCodeFromUnicode(FXFT_ENCODING_APPLE_ROMAN, name_unicode); index = maccode ? FXFT_Get_Char_Index(face, maccode) : FXFT_Get_Name_Index(face, const_cast<char*>(name)); } if (index == 0 || index == 0xffff) return charcode ? static_cast<int>(charcode) : -1; return index; } if (m_Charset == CIDSET_JAPAN1) { if (unicode == '\\') { unicode = '/'; #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ } else if (unicode == 0xa5) { unicode = 0x5c; #endif } } if (!face) return unicode; int err = FXFT_Select_Charmap(face, FXFT_ENCODING_UNICODE); if (err) { int i; for (i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { uint32_t ret = FT_CharCodeFromUnicode( FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]), static_cast<FX_WCHAR>(charcode)); if (ret == 0) continue; FXFT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[i]); unicode = static_cast<FX_WCHAR>(ret); break; } if (i == FXFT_Get_Face_CharmapCount(face) && i) { FXFT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[0]); unicode = static_cast<FX_WCHAR>(charcode); } } if (FXFT_Get_Face_Charmap(face)) { int index = GetGlyphIndex(unicode, pVertGlyph); return index != 0 ? index : -1; } return unicode; } if (!m_Font.GetFace()) return -1; uint16_t cid = CIDFromCharCode(charcode); if (!m_pStreamAcc) { if (m_bType1) return cid; if (m_pFontFile && !m_pCMap->m_pMapping) return cid; if (m_pCMap->m_Coding == CIDCODING_UNKNOWN || !FXFT_Get_Face_Charmap(m_Font.GetFace())) { return cid; } if (FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmap(m_Font.GetFace())) == FXFT_ENCODING_UNICODE) { CFX_WideString unicode_str = UnicodeFromCharCode(charcode); if (unicode_str.IsEmpty()) return -1; charcode = unicode_str.GetAt(0); } return GetGlyphIndex(charcode, pVertGlyph); } uint32_t byte_pos = cid * 2; if (byte_pos + 2 > m_pStreamAcc->GetSize()) return -1; const uint8_t* pdata = m_pStreamAcc->GetData() + byte_pos; return pdata[0] * 256 + pdata[1]; }
int32_t CFGAS_GEFont::GetGlyphIndex(FX_WCHAR wUnicode, FX_BOOL bCharCode) { return GetGlyphIndex(wUnicode, TRUE, nullptr, bCharCode); }