LCOV - code coverage report
Current view: top level - gfx/thebes - gfxFT2FontBase.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 54 71 76.1 %
Date: 2017-07-14 16:53:18 Functions: 8 10 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "gfxFT2FontBase.h"
       7             : #include "gfxFT2Utils.h"
       8             : #include "harfbuzz/hb.h"
       9             : #include "mozilla/Likely.h"
      10             : #include "gfxFontConstants.h"
      11             : #include "gfxFontUtils.h"
      12             : 
      13             : using namespace mozilla::gfx;
      14             : 
      15           8 : gfxFT2FontBase::gfxFT2FontBase(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
      16             :                                cairo_scaled_font_t *aScaledFont,
      17             :                                gfxFontEntry *aFontEntry,
      18           8 :                                const gfxFontStyle *aFontStyle)
      19             :     : gfxFont(aUnscaledFont, aFontEntry, aFontStyle, kAntialiasDefault, aScaledFont),
      20             :       mSpaceGlyph(0),
      21           8 :       mHasMetrics(false)
      22             : {
      23           8 :     cairo_scaled_font_reference(mScaledFont);
      24          16 :     gfxFT2LockedFace face(this);
      25           8 :     mFUnitsConvFactor = face.XScale();
      26           8 : }
      27             : 
      28           0 : gfxFT2FontBase::~gfxFT2FontBase()
      29             : {
      30           0 :     cairo_scaled_font_destroy(mScaledFont);
      31           0 : }
      32             : 
      33             : uint32_t
      34         285 : gfxFT2FontBase::GetGlyph(uint32_t aCharCode)
      35             : {
      36             :     // FcFreeTypeCharIndex needs to lock the FT_Face and can end up searching
      37             :     // through all the postscript glyph names in the font.  Therefore use a
      38             :     // lightweight cache, which is stored on the cairo_font_face_t.
      39             : 
      40             :     cairo_font_face_t *face =
      41         285 :         cairo_scaled_font_get_font_face(CairoScaledFont());
      42             : 
      43         285 :     if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
      44           0 :         return 0;
      45             : 
      46             :     // This cache algorithm and size is based on what is done in
      47             :     // cairo_scaled_font_text_to_glyphs and pango_fc_font_real_get_glyph.  I
      48             :     // think the concept is that adjacent characters probably come mostly from
      49             :     // one Unicode block.  This assumption is probably not so valid with
      50             :     // scripts with large character sets as used for East Asian languages.
      51             : 
      52             :     struct CmapCacheSlot {
      53             :         uint32_t mCharCode;
      54             :         uint32_t mGlyphIndex;
      55             :     };
      56         285 :     const uint32_t kNumSlots = 256;
      57             :     static cairo_user_data_key_t sCmapCacheKey;
      58             : 
      59             :     CmapCacheSlot *slots = static_cast<CmapCacheSlot*>
      60         285 :         (cairo_font_face_get_user_data(face, &sCmapCacheKey));
      61             : 
      62         285 :     if (!slots) {
      63             :         // cairo's caches can keep some cairo_font_faces alive past our last
      64             :         // destroy, so the destroy function (free) for the cache must be
      65             :         // callable from cairo without any assumptions about what other
      66             :         // modules have not been shutdown.
      67             :         slots = static_cast<CmapCacheSlot*>
      68           3 :             (calloc(kNumSlots, sizeof(CmapCacheSlot)));
      69           3 :         if (!slots)
      70           0 :             return 0;
      71             : 
      72             :         cairo_status_t status =
      73           3 :             cairo_font_face_set_user_data(face, &sCmapCacheKey, slots, free);
      74           3 :         if (status != CAIRO_STATUS_SUCCESS) { // OOM
      75           0 :             free(slots);
      76           0 :             return 0;
      77             :         }
      78             : 
      79             :         // Invalidate slot 0 by setting its char code to something that would
      80             :         // never end up in slot 0.  All other slots are already invalid
      81             :         // because they have mCharCode = 0 and a glyph for char code 0 will
      82             :         // always be in the slot 0.
      83           3 :         slots[0].mCharCode = 1;
      84             :     }
      85             : 
      86         285 :     CmapCacheSlot *slot = &slots[aCharCode % kNumSlots];
      87         285 :     if (slot->mCharCode != aCharCode) {
      88          74 :         slot->mCharCode = aCharCode;
      89          74 :         slot->mGlyphIndex = gfxFT2LockedFace(this).GetGlyph(aCharCode);
      90             :     }
      91             : 
      92         285 :     return slot->mGlyphIndex;
      93             : }
      94             : 
      95             : void
      96         285 : gfxFT2FontBase::GetGlyphExtents(uint32_t aGlyph, cairo_text_extents_t* aExtents)
      97             : {
      98         285 :     NS_PRECONDITION(aExtents != nullptr, "aExtents must not be NULL");
      99             : 
     100             :     cairo_glyph_t glyphs[1];
     101         285 :     glyphs[0].index = aGlyph;
     102         285 :     glyphs[0].x = 0.0;
     103         285 :     glyphs[0].y = 0.0;
     104             :     // cairo does some caching for us here but perhaps a small gain could be
     105             :     // made by caching more.  It is usually only the advance that is needed,
     106             :     // so caching only the advance could allow many requests to be cached with
     107             :     // little memory use.  Ideally this cache would be merged with
     108             :     // gfxGlyphExtents.
     109         285 :     cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
     110         285 : }
     111             : 
     112             : const gfxFont::Metrics&
     113        1218 : gfxFT2FontBase::GetHorizontalMetrics()
     114             : {
     115        1218 :     if (mHasMetrics)
     116        1213 :         return mMetrics;
     117             : 
     118          10 :     if (MOZ_UNLIKELY(GetStyle()->size <= 0.0) ||
     119           5 :         MOZ_UNLIKELY(GetStyle()->sizeAdjust == 0.0)) {
     120           0 :         new(&mMetrics) gfxFont::Metrics(); // zero initialize
     121           0 :         mSpaceGlyph = GetGlyph(' ');
     122             :     } else {
     123          10 :         gfxFT2LockedFace face(this);
     124           5 :         face.GetMetrics(&mMetrics, &mSpaceGlyph);
     125             :     }
     126             : 
     127           5 :     SanitizeMetrics(&mMetrics, false);
     128             : 
     129             : #if 0
     130             :     //    printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
     131             :     //    printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
     132             : 
     133             :     fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
     134             :     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
     135             :     fprintf (stderr, "    maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
     136             :     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
     137             :     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
     138             :     fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
     139             : #endif
     140             : 
     141           5 :     mHasMetrics = true;
     142           5 :     return mMetrics;
     143             : }
     144             : 
     145             : // Get the glyphID of a space
     146             : uint32_t
     147         107 : gfxFT2FontBase::GetSpaceGlyph()
     148             : {
     149         107 :     GetHorizontalMetrics();
     150         107 :     return mSpaceGlyph;
     151             : }
     152             : 
     153             : uint32_t
     154         265 : gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
     155             : {
     156         265 :     if (variation_selector) {
     157             :         uint32_t id =
     158           0 :             gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
     159           0 :         if (id) {
     160           0 :             return id;
     161             :         }
     162           0 :         unicode = gfxFontUtils::GetUVSFallback(unicode, variation_selector);
     163           0 :         if (unicode) {
     164           0 :             return GetGlyph(unicode);
     165             :         }
     166           0 :         return 0;
     167             :     }
     168             : 
     169         265 :     return GetGlyph(unicode);
     170             : }
     171             : 
     172             : int32_t
     173         265 : gfxFT2FontBase::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID)
     174             : {
     175             :     cairo_text_extents_t extents;
     176         265 :     GetGlyphExtents(aGID, &extents);
     177             :     // convert to 16.16 fixed point
     178         265 :     return NS_lround(0x10000 * extents.x_advance);
     179             : }
     180             : 
     181             : bool
     182         111 : gfxFT2FontBase::SetupCairoFont(DrawTarget* aDrawTarget)
     183             : {
     184             :     // The scaled font ctm is not relevant right here because
     185             :     // cairo_set_scaled_font does not record the scaled font itself, but
     186             :     // merely the font_face, font_matrix, font_options.  The scaled_font used
     187             :     // for the target can be different from the scaled_font passed to
     188             :     // cairo_set_scaled_font.  (Unfortunately we have measured only for an
     189             :     // identity ctm.)
     190         111 :     cairo_scaled_font_t *cairoFont = CairoScaledFont();
     191             : 
     192         111 :     if (cairo_scaled_font_status(cairoFont) != CAIRO_STATUS_SUCCESS) {
     193             :         // Don't cairo_set_scaled_font as that would propagate the error to
     194             :         // the cairo_t, precluding any further drawing.
     195           0 :         return false;
     196             :     }
     197             :     // Thoughts on which font_options to set on the context:
     198             :     //
     199             :     // cairoFont has been created for screen rendering.
     200             :     //
     201             :     // When the context is being used for screen rendering, we should set
     202             :     // font_options such that the same scaled_font gets used (when the ctm is
     203             :     // the same).  The use of explicit font_options recorded in
     204             :     // CreateScaledFont ensures that this will happen.
     205             :     //
     206             :     // XXXkt: For pdf and ps surfaces, I don't know whether it's better to
     207             :     // remove surface-specific options, or try to draw with the same
     208             :     // scaled_font that was used to measure.  As the same font_face is being
     209             :     // used, its font_options will often override some values anyway (unless
     210             :     // perhaps we remove those from the FcPattern at face creation).
     211             :     //
     212             :     // I can't see any significant difference in printing, irrespective of
     213             :     // what is set here.  It's too late to change things here as measuring has
     214             :     // already taken place.  We should really be measuring with a different
     215             :     // font for pdf and ps surfaces (bug 403513).
     216         111 :     cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), cairoFont);
     217         111 :     return true;
     218             : }

Generated by: LCOV version 1.13