gfx/thebes/gfxFT2FontBase.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     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"
    13 using namespace mozilla::gfx;
    15 gfxFT2FontBase::gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
    16                                gfxFontEntry *aFontEntry,
    17                                const gfxFontStyle *aFontStyle)
    18     : gfxFont(aFontEntry, aFontStyle, kAntialiasDefault, aScaledFont),
    19       mSpaceGlyph(0),
    20       mHasMetrics(false)
    21 {
    22     cairo_scaled_font_reference(mScaledFont);
    23     ConstructFontOptions();
    24 }
    26 gfxFT2FontBase::~gfxFT2FontBase()
    27 {
    28     cairo_scaled_font_destroy(mScaledFont);
    29 }
    31 uint32_t
    32 gfxFT2FontBase::GetGlyph(uint32_t aCharCode)
    33 {
    34     // FcFreeTypeCharIndex needs to lock the FT_Face and can end up searching
    35     // through all the postscript glyph names in the font.  Therefore use a
    36     // lightweight cache, which is stored on the cairo_font_face_t.
    38     cairo_font_face_t *face =
    39         cairo_scaled_font_get_font_face(CairoScaledFont());
    41     if (cairo_font_face_status(face) != CAIRO_STATUS_SUCCESS)
    42         return 0;
    44     // This cache algorithm and size is based on what is done in
    45     // cairo_scaled_font_text_to_glyphs and pango_fc_font_real_get_glyph.  I
    46     // think the concept is that adjacent characters probably come mostly from
    47     // one Unicode block.  This assumption is probably not so valid with
    48     // scripts with large character sets as used for East Asian languages.
    50     struct CmapCacheSlot {
    51         uint32_t mCharCode;
    52         uint32_t mGlyphIndex;
    53     };
    54     const uint32_t kNumSlots = 256;
    55     static cairo_user_data_key_t sCmapCacheKey;
    57     CmapCacheSlot *slots = static_cast<CmapCacheSlot*>
    58         (cairo_font_face_get_user_data(face, &sCmapCacheKey));
    60     if (!slots) {
    61         // cairo's caches can keep some cairo_font_faces alive past our last
    62         // destroy, so the destroy function (free) for the cache must be
    63         // callable from cairo without any assumptions about what other
    64         // modules have not been shutdown.
    65         slots = static_cast<CmapCacheSlot*>
    66             (calloc(kNumSlots, sizeof(CmapCacheSlot)));
    67         if (!slots)
    68             return 0;
    70         cairo_status_t status =
    71             cairo_font_face_set_user_data(face, &sCmapCacheKey, slots, free);
    72         if (status != CAIRO_STATUS_SUCCESS) { // OOM
    73             free(slots);
    74             return 0;
    75         }
    77         // Invalidate slot 0 by setting its char code to something that would
    78         // never end up in slot 0.  All other slots are already invalid
    79         // because they have mCharCode = 0 and a glyph for char code 0 will
    80         // always be in the slot 0.
    81         slots[0].mCharCode = 1;
    82     }
    84     CmapCacheSlot *slot = &slots[aCharCode % kNumSlots];
    85     if (slot->mCharCode != aCharCode) {
    86         slot->mCharCode = aCharCode;
    87         slot->mGlyphIndex = gfxFT2LockedFace(this).GetGlyph(aCharCode);
    88     }
    90     return slot->mGlyphIndex;
    91 }
    93 void
    94 gfxFT2FontBase::GetGlyphExtents(uint32_t aGlyph, cairo_text_extents_t* aExtents)
    95 {
    96     NS_PRECONDITION(aExtents != nullptr, "aExtents must not be NULL");
    98     cairo_glyph_t glyphs[1];
    99     glyphs[0].index = aGlyph;
   100     glyphs[0].x = 0.0;
   101     glyphs[0].y = 0.0;
   102     // cairo does some caching for us here but perhaps a small gain could be
   103     // made by caching more.  It is usually only the advance that is needed,
   104     // so caching only the advance could allow many requests to be cached with
   105     // little memory use.  Ideally this cache would be merged with
   106     // gfxGlyphExtents.
   107     cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
   108 }
   110 const gfxFont::Metrics&
   111 gfxFT2FontBase::GetMetrics()
   112 {
   113     if (mHasMetrics)
   114         return mMetrics;
   116     if (MOZ_UNLIKELY(GetStyle()->size <= 0.0)) {
   117         new(&mMetrics) gfxFont::Metrics(); // zero initialize
   118         mSpaceGlyph = 0;
   119     } else {
   120         gfxFT2LockedFace face(this);
   121         mFUnitsConvFactor = face.XScale();
   122         face.GetMetrics(&mMetrics, &mSpaceGlyph);
   123     }
   125     SanitizeMetrics(&mMetrics, false);
   127 #if 0
   128     //    printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
   129     //    printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
   131     fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
   132     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
   133     fprintf (stderr, "    maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
   134     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
   135     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
   136     fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
   137 #endif
   139     mHasMetrics = true;
   140     return mMetrics;
   141 }
   143 // Get the glyphID of a space
   144 uint32_t
   145 gfxFT2FontBase::GetSpaceGlyph()
   146 {
   147     NS_ASSERTION(GetStyle()->size != 0,
   148                  "forgot to short-circuit a text run with zero-sized font?");
   149     GetMetrics();
   150     return mSpaceGlyph;
   151 }
   153 uint32_t
   154 gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
   155 {
   156     if (variation_selector) {
   157         uint32_t id =
   158             gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
   159         if (id)
   160             return id;
   161         id = gfxFontUtils::GetUVSFallback(unicode, variation_selector);
   162         if (id) {
   163             unicode = id;
   164         }
   165     }
   167     return GetGlyph(unicode);
   168 }
   170 int32_t
   171 gfxFT2FontBase::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
   172 {
   173     cairo_text_extents_t extents;
   174     GetGlyphExtents(aGID, &extents);
   175     // convert to 16.16 fixed point
   176     return NS_lround(0x10000 * extents.x_advance);
   177 }
   179 bool
   180 gfxFT2FontBase::SetupCairoFont(gfxContext *aContext)
   181 {
   182     cairo_t *cr = aContext->GetCairo();
   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     cairo_scaled_font_t *cairoFont = CairoScaledFont();
   192     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         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     cairo_set_scaled_font(cr, cairoFont);
   217     return true;
   218 }
   220 void
   221 gfxFT2FontBase::ConstructFontOptions()
   222 {
   223   NS_LossyConvertUTF16toASCII name(this->GetName());
   224   mFontOptions.mName = name.get();
   226   const gfxFontStyle* style = this->GetStyle();
   227   if (style->style == NS_FONT_STYLE_ITALIC) {
   228     if (style->weight == NS_FONT_WEIGHT_BOLD) {
   229       mFontOptions.mStyle = FontStyle::BOLD_ITALIC;
   230     } else {
   231       mFontOptions.mStyle = FontStyle::ITALIC;
   232     }
   233   } else {
   234     if (style->weight == NS_FONT_WEIGHT_BOLD) {
   235       mFontOptions.mStyle = FontStyle::BOLD;
   236     } else {
   237       mFontOptions.mStyle = FontStyle::NORMAL;
   238     }
   239   }
   240 }

mercurial