// gfxOS2Font::GetMetrics() // return the metrics of the current font using the gfxFont metrics structure. // If the metrics are not available yet, compute them using the FreeType // function on the font. (This is partly based on the respective function from // gfxPangoFonts) const gfxFont::Metrics& gfxOS2Font::GetMetrics() { #ifdef DEBUG_thebes_1 printf("gfxOS2Font[%#x]::GetMetrics()\n", (unsigned)this); #endif if (mMetrics) { return *mMetrics; } // whatever happens below, we can always create the metrics mMetrics = new gfxFont::Metrics; mSpaceGlyph = 0; // round size to integer pixels, this is to get full pixels for layout // together with internal/external leading (see below) mMetrics->emHeight = NS_floor(GetStyle()->size + 0.5); FT_Face face = cairo_ft_scaled_font_lock_face(CairoScaledFont()); if (!face) { // Abort here already, otherwise we crash in the following // this can happen if the font-size requested is zero. FillMetricsDefaults(mMetrics); return *mMetrics; } if (!face->charmap) { // Also abort, if the charmap isn't loaded; then the char // lookups won't work. This happens for fonts without Unicode // charmap. cairo_ft_scaled_font_unlock_face(CairoScaledFont()); FillMetricsDefaults(mMetrics); return *mMetrics; } // compute font scaling factors gfxFloat emUnit = 1.0 * face->units_per_EM; gfxFloat xScale = face->size->metrics.x_ppem / emUnit; gfxFloat yScale = face->size->metrics.y_ppem / emUnit; FT_UInt gid; // glyph ID // properties of space gid = FT_Get_Char_Index(face, ' '); if (gid) { // Load glyph into glyph slot. Use load_default here to get results in // 26.6 fractional pixel format which is what is used for all other // characters in gfxOS2FontGroup::CreateGlyphRunsFT. FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT); // glyph width doesn't work for spaces, use advance instead mMetrics->spaceWidth = face->glyph->advance.x >> 6; // save the space glyph mSpaceGlyph = gid; } else {
PRBool gfxDWriteFont::SetupCairoFont(gfxContext *aContext) { cairo_scaled_font_t *scaledFont = CairoScaledFont(); if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) { // Don't cairo_set_scaled_font as that would propagate the error to // the cairo_t, precluding any further drawing. return PR_FALSE; } cairo_set_scaled_font(aContext->GetCairo(), scaledFont); return PR_TRUE; }
void gfxFT2FontBase::GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents) { NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL"); cairo_glyph_t glyphs[1]; glyphs[0].index = aGlyph; glyphs[0].x = 0.0; glyphs[0].y = 0.0; // cairo does some caching for us here but perhaps a small gain could be // made by caching more. It is usually only the advance that is needed, // so caching only the advance could allow many requests to be cached with // little memory use. Ideally this cache would be merged with // gfxGlyphExtents. cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents); }
bool gfxFT2FontBase::SetupCairoFont(gfxContext *aContext) { cairo_t *cr = aContext->GetCairo(); // The scaled font ctm is not relevant right here because // cairo_set_scaled_font does not record the scaled font itself, but // merely the font_face, font_matrix, font_options. The scaled_font used // for the target can be different from the scaled_font passed to // cairo_set_scaled_font. (Unfortunately we have measured only for an // identity ctm.) cairo_scaled_font_t *cairoFont = CairoScaledFont(); if (cairo_scaled_font_status(cairoFont) != CAIRO_STATUS_SUCCESS) { // Don't cairo_set_scaled_font as that would propagate the error to // the cairo_t, precluding any further drawing. return PR_FALSE; } // Thoughts on which font_options to set on the context: // // cairoFont has been created for screen rendering. // // When the context is being used for screen rendering, we should set // font_options such that the same scaled_font gets used (when the ctm is // the same). The use of explicit font_options recorded in // CreateScaledFont ensures that this will happen. // // XXXkt: For pdf and ps surfaces, I don't know whether it's better to // remove surface-specific options, or try to draw with the same // scaled_font that was used to measure. As the same font_face is being // used, its font_options will often override some values anyway (unless // perhaps we remove those from the FcPattern at face creation). // // I can't see any significant difference in printing, irrespective of // what is set here. It's too late to change things here as measuring has // already taken place. We should really be measuring with a different // font for pdf and ps surfaces (bug 403513). cairo_set_scaled_font(cr, cairoFont); return PR_TRUE; }
PRUint32 gfxFT2FontBase::GetGlyph(PRUint32 aCharCode) { // FcFreeTypeCharIndex needs to lock the FT_Face and can end up searching // through all the postscript glyph names in the font. Therefore use a // lightweight cache, which is stored on the cairo_font_face_t. cairo_font_face_t *face = cairo_scaled_font_get_font_face(CairoScaledFont()); if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS) return 0; // This cache algorithm and size is based on what is done in // cairo_scaled_font_text_to_glyphs and pango_fc_font_real_get_glyph. I // think the concept is that adjacent characters probably come mostly from // one Unicode block. This assumption is probably not so valid with // scripts with large character sets as used for East Asian languages. struct CmapCacheSlot { PRUint32 mCharCode; PRUint32 mGlyphIndex; }; const PRUint32 kNumSlots = 256; static cairo_user_data_key_t sCmapCacheKey; CmapCacheSlot *slots = static_cast<CmapCacheSlot*> (cairo_font_face_get_user_data(face, &sCmapCacheKey)); if (!slots) { // cairo's caches can keep some cairo_font_faces alive past our last // destroy, so the destroy function (free) for the cache must be // callable from cairo without any assumptions about what other // modules have not been shutdown. slots = static_cast<CmapCacheSlot*> (calloc(kNumSlots, sizeof(CmapCacheSlot))); if (!slots) return 0; cairo_status_t status = cairo_font_face_set_user_data(face, &sCmapCacheKey, slots, free); if (status != CAIRO_STATUS_SUCCESS) { // OOM free(slots); return 0; } // Invalidate slot 0 by setting its char code to something that would // never end up in slot 0. All other slots are already invalid // because they have mCharCode = 0 and a glyph for char code 0 will // always be in the slot 0. slots[0].mCharCode = 1; } CmapCacheSlot *slot = &slots[aCharCode % kNumSlots]; if (slot->mCharCode != aCharCode) { slot->mCharCode = aCharCode; slot->mGlyphIndex = gfxFT2LockedFace(this).GetGlyph(aCharCode); } return slot->mGlyphIndex; }