tor-browser

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

InspectorFontFace.cpp (10779B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "InspectorFontFace.h"
      8 
      9 #include "brotli/decode.h"
     10 #include "gfxPlatformFontList.h"
     11 #include "gfxTextRun.h"
     12 #include "gfxUserFontSet.h"
     13 #include "harfbuzz/hb-ot.h"
     14 #include "mozilla/ServoBindings.h"
     15 #include "mozilla/dom/CSSFontFaceRule.h"
     16 #include "mozilla/dom/FontFaceSet.h"
     17 #include "mozilla/gfx/2D.h"
     18 #include "nsFontFaceLoader.h"
     19 #include "zlib.h"
     20 
     21 namespace mozilla {
     22 namespace dom {
     23 
     24 InspectorFontFace::InspectorFontFace(gfxFontEntry* aFontEntry,
     25                                     gfxFontGroup* aFontGroup,
     26                                     FontMatchType aMatchType)
     27    : mFontEntry(aFontEntry), mFontGroup(aFontGroup), mMatchType(aMatchType) {
     28  MOZ_COUNT_CTOR(InspectorFontFace);
     29 }
     30 
     31 InspectorFontFace::~InspectorFontFace() { MOZ_COUNT_DTOR(InspectorFontFace); }
     32 
     33 bool InspectorFontFace::FromFontGroup() {
     34  return bool(mMatchType.kind & FontMatchType::Kind::kFontGroup);
     35 }
     36 
     37 bool InspectorFontFace::FromLanguagePrefs() {
     38  return bool(mMatchType.kind & FontMatchType::Kind::kPrefsFallback);
     39 }
     40 
     41 bool InspectorFontFace::FromSystemFallback() {
     42  return bool(mMatchType.kind & FontMatchType::Kind::kSystemFallback);
     43 }
     44 
     45 void InspectorFontFace::GetName(nsAString& aName) {
     46  if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
     47    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
     48    aName.Append(NS_ConvertUTF8toUTF16(mFontEntry->mUserFontData->mRealName));
     49  } else {
     50    aName.Append(NS_ConvertUTF8toUTF16(mFontEntry->RealFaceName()));
     51  }
     52 }
     53 
     54 void InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) {
     55  aCSSFamilyName.Append(NS_ConvertUTF8toUTF16(mFontEntry->FamilyName()));
     56 }
     57 
     58 void InspectorFontFace::GetCSSGeneric(nsAString& aName) {
     59  if (mMatchType.generic != StyleGenericFontFamily::None) {
     60    aName.AssignASCII(gfxPlatformFontList::GetGenericName(mMatchType.generic));
     61  } else {
     62    aName.Truncate(0);
     63  }
     64 }
     65 
     66 void InspectorFontFace::GetNameString(uint16_t aNameId, nsAString& aResult) {
     67  gfxFontEntry::AutoHBFace face = mFontEntry->GetHBFace();
     68  unsigned int textSize = 0;
     69  unsigned int len = hb_ot_name_get_utf16(face, aNameId, HB_LANGUAGE_INVALID,
     70                                          &textSize, nullptr);
     71  if (len) {
     72    aResult.SetLength(len + 1);  // Ensure there is space for NUL terminator.
     73    textSize = len + 1;  // Tell HB the total size of the available buffer.
     74    len = hb_ot_name_get_utf16(
     75        face, aNameId, HB_LANGUAGE_INVALID, &textSize,
     76        reinterpret_cast<uint16_t*>(aResult.BeginWriting()));
     77    aResult.SetLength(len);  // Size the string to exclude terminator.
     78  } else {
     79    aResult.Truncate(0);
     80  }
     81 }
     82 
     83 CSSFontFaceRule* InspectorFontFace::GetRule() {
     84  if (!mRule) {
     85    // check whether this font entry is associated with an @font-face rule
     86    // in the relevant font group's user font set
     87    StyleLockedFontFaceRule* rule = nullptr;
     88    if (mFontEntry->IsUserFont()) {
     89      auto* fontFaceSet =
     90          static_cast<FontFaceSetImpl*>(mFontGroup->GetUserFontSet());
     91      if (fontFaceSet) {
     92        rule = fontFaceSet->FindRuleForEntry(mFontEntry);
     93      }
     94    }
     95    if (rule) {
     96      // XXX It would be better if we can share this with CSSOM tree,
     97      // but that may require us to create another map, which is not
     98      // great either. As far as they would use the same backend, and
     99      // we don't really support mutating @font-face rule via CSSOM,
    100      // it's probably fine for now.
    101      uint32_t line, column;
    102      Servo_FontFaceRule_GetSourceLocation(rule, &line, &column);
    103      mRule =
    104          new CSSFontFaceRule(do_AddRef(rule), nullptr, nullptr, line, column);
    105    }
    106  }
    107  return mRule;
    108 }
    109 
    110 int32_t InspectorFontFace::SrcIndex() {
    111  if (mFontEntry->IsUserFont()) {
    112    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
    113    return mFontEntry->mUserFontData->mSrcIndex;
    114  }
    115 
    116  return -1;
    117 }
    118 
    119 void InspectorFontFace::GetURI(nsAString& aURI) {
    120  aURI.Truncate();
    121  if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
    122    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
    123    if (mFontEntry->mUserFontData->mURI) {
    124      nsAutoCString spec;
    125      mFontEntry->mUserFontData->mURI->GetSpec(spec);
    126      AppendUTF8toUTF16(spec, aURI);
    127    }
    128  }
    129 }
    130 
    131 void InspectorFontFace::GetLocalName(nsAString& aLocalName) {
    132  aLocalName.Truncate();
    133  if (mFontEntry->IsLocalUserFont()) {
    134    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
    135    aLocalName.Append(
    136        NS_ConvertUTF8toUTF16(mFontEntry->mUserFontData->mLocalName));
    137  }
    138 }
    139 
    140 void InspectorFontFace::GetFormat(nsAString& aFormat) {
    141  aFormat.Truncate();
    142  if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
    143    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
    144    switch (mFontEntry->mUserFontData->mFormatHint) {
    145      case StyleFontFaceSourceFormatKeyword::None:
    146        break;
    147      case StyleFontFaceSourceFormatKeyword::Collection:
    148        aFormat.AssignLiteral("collection");
    149        break;
    150      case StyleFontFaceSourceFormatKeyword::Opentype:
    151        aFormat.AssignLiteral("opentype");
    152        break;
    153      case StyleFontFaceSourceFormatKeyword::Truetype:
    154        aFormat.AssignLiteral("truetype");
    155        break;
    156      case StyleFontFaceSourceFormatKeyword::EmbeddedOpentype:
    157        aFormat.AssignLiteral("embedded-opentype");
    158        break;
    159      case StyleFontFaceSourceFormatKeyword::Svg:
    160        aFormat.AssignLiteral("svg");
    161        break;
    162      case StyleFontFaceSourceFormatKeyword::Woff:
    163        aFormat.AssignLiteral("woff");
    164        break;
    165      case StyleFontFaceSourceFormatKeyword::Woff2:
    166        aFormat.AssignLiteral("woff2");
    167        break;
    168      case StyleFontFaceSourceFormatKeyword::Unknown:
    169        aFormat.AssignLiteral("unknown!");
    170        break;
    171    }
    172  }
    173 }
    174 
    175 void InspectorFontFace::GetMetadata(nsAString& aMetadata) {
    176  aMetadata.Truncate();
    177  if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
    178    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
    179    const gfxUserFontData* userFontData = mFontEntry->mUserFontData.get();
    180    if (userFontData->mMetadata.Length() && userFontData->mMetaOrigLen) {
    181      nsAutoCString str;
    182      str.SetLength(userFontData->mMetaOrigLen);
    183      if (str.Length() == userFontData->mMetaOrigLen) {
    184        switch (userFontData->mCompression) {
    185          case gfxUserFontData::kZlibCompression: {
    186            uLongf destLen = userFontData->mMetaOrigLen;
    187            if (uncompress((Bytef*)(str.BeginWriting()), &destLen,
    188                           (const Bytef*)(userFontData->mMetadata.Elements()),
    189                           userFontData->mMetadata.Length()) == Z_OK &&
    190                destLen == userFontData->mMetaOrigLen) {
    191              AppendUTF8toUTF16(str, aMetadata);
    192            }
    193          } break;
    194          case gfxUserFontData::kBrotliCompression: {
    195            size_t decodedSize = userFontData->mMetaOrigLen;
    196            if (BrotliDecoderDecompress(userFontData->mMetadata.Length(),
    197                                        userFontData->mMetadata.Elements(),
    198                                        &decodedSize,
    199                                        (uint8_t*)str.BeginWriting()) == 1 &&
    200                decodedSize == userFontData->mMetaOrigLen) {
    201              AppendUTF8toUTF16(str, aMetadata);
    202            }
    203          } break;
    204        }
    205      }
    206    }
    207  }
    208 }
    209 
    210 // Append an OpenType tag to a string as a 4-ASCII-character code.
    211 static void AppendTagAsASCII(nsAString& aString, uint32_t aTag) {
    212  aString.AppendPrintf("%c%c%c%c", (aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
    213                       (aTag >> 8) & 0xff, aTag & 0xff);
    214 }
    215 
    216 void InspectorFontFace::GetVariationAxes(
    217    nsTArray<InspectorVariationAxis>& aResult, ErrorResult& aRV) {
    218  if (!mFontEntry->HasVariations()) {
    219    return;
    220  }
    221  AutoTArray<gfxFontVariationAxis, 4> axes;
    222  mFontEntry->GetVariationAxes(axes);
    223  MOZ_ASSERT(!axes.IsEmpty());
    224  if (!aResult.SetCapacity(axes.Length(), mozilla::fallible)) {
    225    aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
    226    return;
    227  }
    228  for (auto a : axes) {
    229    InspectorVariationAxis& axis = *aResult.AppendElement();
    230    AppendTagAsASCII(axis.mTag, a.mTag);
    231    axis.mName.Append(NS_ConvertUTF8toUTF16(a.mName));
    232    axis.mMinValue = a.mMinValue;
    233    axis.mMaxValue = a.mMaxValue;
    234    axis.mDefaultValue = a.mDefaultValue;
    235  }
    236 }
    237 
    238 void InspectorFontFace::GetVariationInstances(
    239    nsTArray<InspectorVariationInstance>& aResult, ErrorResult& aRV) {
    240  if (!mFontEntry->HasVariations()) {
    241    return;
    242  }
    243  AutoTArray<gfxFontVariationInstance, 16> instances;
    244  mFontEntry->GetVariationInstances(instances);
    245  if (!aResult.SetCapacity(instances.Length(), mozilla::fallible)) {
    246    aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
    247    return;
    248  }
    249  for (const auto& i : instances) {
    250    InspectorVariationInstance& inst = *aResult.AppendElement();
    251    inst.mName.Append(NS_ConvertUTF8toUTF16(i.mName));
    252    // inst.mValues is a webidl sequence<>, which is a fallible array,
    253    // so we are required to use fallible SetCapacity and AppendElement calls,
    254    // and check the result. In practice we don't expect failure here; the
    255    // list of values cannot get huge because of limits in the font format.
    256    if (!inst.mValues.SetCapacity(i.mValues.Length(), mozilla::fallible)) {
    257      aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
    258      return;
    259    }
    260    for (const auto& v : i.mValues) {
    261      InspectorVariationValue value;
    262      AppendTagAsASCII(value.mAxis, v.mAxis);
    263      value.mValue = v.mValue;
    264      // This won't fail, because of SetCapacity above.
    265      (void)inst.mValues.AppendElement(value, mozilla::fallible);
    266    }
    267  }
    268 }
    269 
    270 void InspectorFontFace::GetFeatures(nsTArray<InspectorFontFeature>& aResult,
    271                                    ErrorResult& aRV) {
    272  AutoTArray<gfxFontFeatureInfo, 64> features;
    273  mFontEntry->GetFeatureInfo(features);
    274  if (features.IsEmpty()) {
    275    return;
    276  }
    277  if (!aResult.SetCapacity(features.Length(), mozilla::fallible)) {
    278    aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
    279    return;
    280  }
    281  for (auto& f : features) {
    282    InspectorFontFeature& feat = *aResult.AppendElement();
    283    AppendTagAsASCII(feat.mTag, f.mTag);
    284    AppendTagAsASCII(feat.mScript, f.mScript);
    285    AppendTagAsASCII(feat.mLanguageSystem, f.mLangSys);
    286  }
    287 }
    288 
    289 void InspectorFontFace::GetRanges(nsTArray<RefPtr<nsRange>>& aResult) {
    290  aResult = mRanges.Clone();
    291 }
    292 
    293 void InspectorFontFace::AddRange(nsRange* aRange) {
    294  mRanges.AppendElement(aRange);
    295 }
    296 
    297 }  // namespace dom
    298 }  // namespace mozilla