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