tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gfxFT2Fonts.cpp (8051B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      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 #if defined(MOZ_WIDGET_GTK)
      7 #  include "gfxPlatformGtk.h"
      8 #  define gfxToolkitPlatform gfxPlatformGtk
      9 #elif defined(XP_WIN)
     10 #  include "gfxWindowsPlatform.h"
     11 #  define gfxToolkitPlatform gfxWindowsPlatform
     12 #elif defined(ANDROID)
     13 #  include "gfxAndroidPlatform.h"
     14 #  define gfxToolkitPlatform gfxAndroidPlatform
     15 #endif
     16 
     17 #include "gfxTypes.h"
     18 #include "gfxFT2Fonts.h"
     19 #include "gfxFT2FontBase.h"
     20 #include "gfxFT2Utils.h"
     21 #include "gfxFT2FontList.h"
     22 #include "gfxTextRun.h"
     23 #include <locale.h>
     24 #include "nsGkAtoms.h"
     25 #include "nsTArray.h"
     26 #include "nsCRT.h"
     27 #include "nsXULAppAPI.h"
     28 
     29 #include "mozilla/Logging.h"
     30 #include "prinit.h"
     31 
     32 #include "mozilla/MemoryReporting.h"
     33 #include "mozilla/Preferences.h"
     34 #include "mozilla/gfx/2D.h"
     35 
     36 using namespace mozilla;
     37 using namespace mozilla::gfx;
     38 
     39 /**
     40 * gfxFT2Font
     41 */
     42 
     43 bool gfxFT2Font::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
     44                           uint32_t aOffset, uint32_t aLength, Script aScript,
     45                           nsAtom* aLanguage, bool aVertical,
     46                           RoundingFlags aRounding,
     47                           gfxShapedText* aShapedText) {
     48  if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
     49                          aLanguage, aVertical, aRounding, aShapedText)) {
     50    // harfbuzz must have failed(?!), just render raw glyphs
     51    AddRange(aText, aOffset, aLength, aShapedText);
     52    PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
     53                     aShapedText);
     54  }
     55 
     56  return true;
     57 }
     58 
     59 void gfxFT2Font::AddRange(const char16_t* aText, uint32_t aOffset,
     60                          uint32_t aLength, gfxShapedText* aShapedText) {
     61  typedef gfxShapedText::CompressedGlyph CompressedGlyph;
     62 
     63  const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
     64  // we'll pass this in/figure it out dynamically, but at this point there can
     65  // be only one face.
     66  gfxFT2LockedFace faceLock(this);
     67  FT_Face face = faceLock.get();
     68 
     69  CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs();
     70 
     71  const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
     72 
     73  FT_UInt spaceGlyph = GetSpaceGlyph();
     74 
     75  for (uint32_t i = 0; i < aLength; i++, aOffset++) {
     76    char16_t ch = aText[i];
     77 
     78    if (ch == 0) {
     79      // treat this null byte as a missing glyph, don't create a glyph for it
     80      aShapedText->SetMissingGlyph(aOffset, 0, this);
     81      continue;
     82    }
     83 
     84    NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
     85 
     86    if (cgdNext) {
     87      cgd = cgdNext;
     88      cgdNext = nullptr;
     89    } else {
     90      cgd = GetGlyphDataForChar(face, ch);
     91    }
     92 
     93    FT_UInt gid = cgd->glyphIndex;
     94    int32_t advance = 0;
     95 
     96    if (gid == 0) {
     97      advance = -1;  // trigger the missing glyphs case below
     98    } else {
     99      // find next character and its glyph -- in case they exist
    100      // and exist in the current font face -- to compute kerning
    101      char16_t chNext = 0;
    102      FT_UInt gidNext = 0;
    103      FT_Pos lsbDeltaNext = 0;
    104 
    105      if (FT_HAS_KERNING(face) && i + 1 < aLength) {
    106        chNext = aText[i + 1];
    107        if (chNext != 0) {
    108          cgdNext = GetGlyphDataForChar(face, chNext);
    109          gidNext = cgdNext->glyphIndex;
    110          if (gidNext && gidNext != spaceGlyph)
    111            lsbDeltaNext = cgdNext->lsbDelta;
    112        }
    113      }
    114 
    115      advance = cgd->xAdvance;
    116 
    117      // now add kerning to the current glyph's advance
    118      if (chNext && gidNext) {
    119        FT_Vector kerning;
    120        kerning.x = 0;
    121        FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning);
    122        advance += kerning.x;
    123        if (cgd->rsbDelta - lsbDeltaNext >= 32) {
    124          advance -= 64;
    125        } else if (cgd->rsbDelta - lsbDeltaNext < -32) {
    126          advance += 64;
    127        }
    128      }
    129 
    130      // convert 26.6 fixed point to app units
    131      // round rather than truncate to nearest pixel
    132      // because these advances are often scaled
    133      advance = ((advance * appUnitsPerDevUnit + 32) >> 6);
    134    }
    135 
    136    if (advance >= 0 && CompressedGlyph::IsSimpleAdvance(advance) &&
    137        CompressedGlyph::IsSimpleGlyphID(gid)) {
    138      charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
    139    } else if (gid == 0) {
    140      // gid = 0 only happens when the glyph is missing from the font
    141      aShapedText->SetMissingGlyph(aOffset, ch, this);
    142    } else {
    143      gfxTextRun::DetailedGlyph details;
    144      details.mGlyphID = gid;
    145      NS_ASSERTION(details.mGlyphID == gid,
    146                   "Seriously weird glyph ID detected!");
    147      details.mAdvance = advance;
    148      aShapedText->SetDetailedGlyphs(aOffset, 1, &details);
    149    }
    150  }
    151 }
    152 
    153 gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
    154                       RefPtr<mozilla::gfx::SharedFTFace>&& aFTFace,
    155                       FT2FontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
    156                       int aLoadFlags)
    157    : gfxFT2FontBase(aUnscaledFont, std::move(aFTFace), aFontEntry, aFontStyle,
    158                     aLoadFlags, aFontStyle->NeedsSyntheticBold(aFontEntry)),
    159      mCharGlyphCache(32) {
    160  NS_ASSERTION(mFontEntry,
    161               "Unable to find font entry for font.  Something is whack.");
    162  InitMetrics();
    163 }
    164 
    165 gfxFT2Font::~gfxFT2Font() {}
    166 
    167 already_AddRefed<ScaledFont> gfxFT2Font::GetScaledFont(
    168    const TextRunDrawParams& aRunParams) {
    169  if (ScaledFont* scaledFont = mAzureScaledFont) {
    170    return do_AddRef(scaledFont);
    171  }
    172 
    173  RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForFreeTypeFont(
    174      GetUnscaledFont(), GetAdjustedSize(), mFTFace,
    175      GetStyle()->NeedsSyntheticBold(GetFontEntry()));
    176  if (!newScaledFont) {
    177    return nullptr;
    178  }
    179 
    180  InitializeScaledFont(newScaledFont);
    181 
    182  if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
    183    newScaledFont.forget().leak();
    184  }
    185  ScaledFont* scaledFont = mAzureScaledFont;
    186  return do_AddRef(scaledFont);
    187 }
    188 
    189 bool gfxFT2Font::ShouldHintMetrics() const {
    190  return !gfxPlatform::GetPlatform()->RequiresLinearZoom();
    191 }
    192 
    193 void gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch,
    194                                      CachedGlyphData* gd) {
    195  if (!face->charmap || (face->charmap->encoding != FT_ENCODING_UNICODE &&
    196                         face->charmap->encoding != FT_ENCODING_MS_SYMBOL)) {
    197    if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE) &&
    198        FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_MS_SYMBOL)) {
    199      NS_WARNING("failed to select Unicode or symbol charmap!");
    200    }
    201  }
    202  FT_UInt gid = FT_Get_Char_Index(face, ch);
    203 
    204  if (gid == 0) {
    205    // this font doesn't support this char!
    206    NS_ASSERTION(gid != 0,
    207                 "We don't have a glyph, but font indicated that it supported "
    208                 "this char in tables?");
    209    gd->glyphIndex = 0;
    210    return;
    211  }
    212 
    213  FT_Error err = Factory::LoadFTGlyph(face, gid, mFTLoadFlags);
    214 
    215  if (err) {
    216    // hmm, this is weird, we failed to load a glyph that we had?
    217    NS_WARNING("Failed to load glyph that we got from Get_Char_index");
    218 
    219    gd->glyphIndex = 0;
    220    return;
    221  }
    222 
    223  gd->glyphIndex = gid;
    224  gd->lsbDelta = face->glyph->lsb_delta;
    225  gd->rsbDelta = face->glyph->rsb_delta;
    226  gd->xAdvance = face->glyph->advance.x;
    227  if (gd->xAdvance) {
    228    gd->xAdvance += GetEmboldenStrength(face).x;
    229  }
    230 }
    231 
    232 void gfxFT2Font::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    233                                        FontCacheSizes* aSizes) const {
    234  gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    235  aSizes->mFontInstances +=
    236      mCharGlyphCache.ShallowSizeOfExcludingThis(aMallocSizeOf);
    237 }
    238 
    239 void gfxFT2Font::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    240                                        FontCacheSizes* aSizes) const {
    241  aSizes->mFontInstances += aMallocSizeOf(this);
    242  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    243 }