forked from mirrors/gecko-dev
		
	 265e672179
			
		
	
	
		265e672179
		
	
	
	
	
		
			
			# ignore-this-changeset --HG-- extra : amend_source : 4d301d3b0b8711c4692392aa76088ba7fd7d1022
		
			
				
	
	
		
			291 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "InspectorFontFace.h"
 | |
| 
 | |
| #include "gfxPlatformFontList.h"
 | |
| #include "gfxTextRun.h"
 | |
| #include "gfxUserFontSet.h"
 | |
| #include "nsFontFaceLoader.h"
 | |
| #include "mozilla/gfx/2D.h"
 | |
| #include "brotli/decode.h"
 | |
| #include "zlib.h"
 | |
| #include "mozilla/dom/CSSFontFaceRule.h"
 | |
| #include "mozilla/dom/FontFaceSet.h"
 | |
| #include "mozilla/ServoBindings.h"
 | |
| #include "mozilla/Unused.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| bool InspectorFontFace::FromFontGroup() {
 | |
|   return bool(mMatchType & gfxTextRange::MatchType::kFontGroup);
 | |
| }
 | |
| 
 | |
| bool InspectorFontFace::FromLanguagePrefs() {
 | |
|   return bool(mMatchType & gfxTextRange::MatchType::kPrefsFallback);
 | |
| }
 | |
| 
 | |
| bool InspectorFontFace::FromSystemFallback() {
 | |
|   return bool(mMatchType & gfxTextRange::MatchType::kSystemFallback);
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetName(nsAString& aName) {
 | |
|   if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     aName.Append(NS_ConvertUTF8toUTF16(mFontEntry->mUserFontData->mRealName));
 | |
|   } else {
 | |
|     aName.Append(NS_ConvertUTF8toUTF16(mFontEntry->RealFaceName()));
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) {
 | |
|   aCSSFamilyName.Append(NS_ConvertUTF8toUTF16(mFontEntry->FamilyName()));
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetCSSGeneric(nsAString& aName) {
 | |
|   auto genericType =
 | |
|       FontFamilyType(mMatchType & gfxTextRange::MatchType::kGenericMask);
 | |
|   if (genericType >= FontFamilyType::eFamily_generic_first &&
 | |
|       genericType <= FontFamilyType::eFamily_generic_last) {
 | |
|     aName.AssignASCII(gfxPlatformFontList::GetGenericName(genericType));
 | |
|   } else {
 | |
|     aName.Truncate(0);
 | |
|   }
 | |
| }
 | |
| 
 | |
| CSSFontFaceRule* InspectorFontFace::GetRule() {
 | |
|   if (!mRule) {
 | |
|     // check whether this font entry is associated with an @font-face rule
 | |
|     // in the relevant font group's user font set
 | |
|     RawServoFontFaceRule* rule = nullptr;
 | |
|     if (mFontEntry->IsUserFont()) {
 | |
|       FontFaceSet::UserFontSet* fontSet =
 | |
|           static_cast<FontFaceSet::UserFontSet*>(mFontGroup->GetUserFontSet());
 | |
|       if (fontSet) {
 | |
|         FontFaceSet* fontFaceSet = fontSet->GetFontFaceSet();
 | |
|         if (fontFaceSet) {
 | |
|           rule = fontFaceSet->FindRuleForEntry(mFontEntry);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (rule) {
 | |
|       // XXX It would be better if we can share this with CSSOM tree,
 | |
|       // but that may require us to create another map, which is not
 | |
|       // great either. As far as they would use the same backend, and
 | |
|       // we don't really support mutating @font-face rule via CSSOM,
 | |
|       // it's probably fine for now.
 | |
|       uint32_t line, column;
 | |
|       Servo_FontFaceRule_GetSourceLocation(rule, &line, &column);
 | |
|       mRule =
 | |
|           new CSSFontFaceRule(do_AddRef(rule), nullptr, nullptr, line, column);
 | |
|     }
 | |
|   }
 | |
|   return mRule;
 | |
| }
 | |
| 
 | |
| int32_t InspectorFontFace::SrcIndex() {
 | |
|   if (mFontEntry->IsUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     return mFontEntry->mUserFontData->mSrcIndex;
 | |
|   }
 | |
| 
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetURI(nsAString& aURI) {
 | |
|   aURI.Truncate();
 | |
|   if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     if (mFontEntry->mUserFontData->mURI) {
 | |
|       nsAutoCString spec;
 | |
|       mFontEntry->mUserFontData->mURI->GetSpec(spec);
 | |
|       AppendUTF8toUTF16(spec, aURI);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetLocalName(nsAString& aLocalName) {
 | |
|   aLocalName.Truncate();
 | |
|   if (mFontEntry->IsLocalUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     aLocalName.Append(
 | |
|         NS_ConvertUTF8toUTF16(mFontEntry->mUserFontData->mLocalName));
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void AppendToFormat(nsAString& aResult, const char* aFormat) {
 | |
|   if (!aResult.IsEmpty()) {
 | |
|     aResult.Append(',');
 | |
|   }
 | |
|   aResult.AppendASCII(aFormat);
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetFormat(nsAString& aFormat) {
 | |
|   aFormat.Truncate();
 | |
|   if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     uint32_t formatFlags = mFontEntry->mUserFontData->mFormat;
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_OPENTYPE) {
 | |
|       AppendToFormat(aFormat, "opentype");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE) {
 | |
|       AppendToFormat(aFormat, "truetype");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT) {
 | |
|       AppendToFormat(aFormat, "truetype-aat");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_EOT) {
 | |
|       AppendToFormat(aFormat, "embedded-opentype");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_SVG) {
 | |
|       AppendToFormat(aFormat, "svg");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF) {
 | |
|       AppendToFormat(aFormat, "woff");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF2) {
 | |
|       AppendToFormat(aFormat, "woff2");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_OPENTYPE_VARIATIONS) {
 | |
|       AppendToFormat(aFormat, "opentype-variations");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_VARIATIONS) {
 | |
|       AppendToFormat(aFormat, "truetype-variations");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF_VARIATIONS) {
 | |
|       AppendToFormat(aFormat, "woff-variations");
 | |
|     }
 | |
|     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF2_VARIATIONS) {
 | |
|       AppendToFormat(aFormat, "woff2-variations");
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetMetadata(nsAString& aMetadata) {
 | |
|   aMetadata.Truncate();
 | |
|   if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
 | |
|     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
 | |
|     const gfxUserFontData* userFontData = mFontEntry->mUserFontData.get();
 | |
|     if (userFontData->mMetadata.Length() && userFontData->mMetaOrigLen) {
 | |
|       nsAutoCString str;
 | |
|       str.SetLength(userFontData->mMetaOrigLen);
 | |
|       if (str.Length() == userFontData->mMetaOrigLen) {
 | |
|         switch (userFontData->mCompression) {
 | |
|           case gfxUserFontData::kZlibCompression: {
 | |
|             uLongf destLen = userFontData->mMetaOrigLen;
 | |
|             if (uncompress((Bytef*)(str.BeginWriting()), &destLen,
 | |
|                            (const Bytef*)(userFontData->mMetadata.Elements()),
 | |
|                            userFontData->mMetadata.Length()) == Z_OK &&
 | |
|                 destLen == userFontData->mMetaOrigLen) {
 | |
|               AppendUTF8toUTF16(str, aMetadata);
 | |
|             }
 | |
|           } break;
 | |
|           case gfxUserFontData::kBrotliCompression: {
 | |
|             size_t decodedSize = userFontData->mMetaOrigLen;
 | |
|             if (BrotliDecoderDecompress(userFontData->mMetadata.Length(),
 | |
|                                         userFontData->mMetadata.Elements(),
 | |
|                                         &decodedSize,
 | |
|                                         (uint8_t*)str.BeginWriting()) == 1 &&
 | |
|                 decodedSize == userFontData->mMetaOrigLen) {
 | |
|               AppendUTF8toUTF16(str, aMetadata);
 | |
|             }
 | |
|           } break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Append an OpenType tag to a string as a 4-ASCII-character code.
 | |
| static void AppendTagAsASCII(nsAString& aString, uint32_t aTag) {
 | |
|   aString.AppendPrintf("%c%c%c%c", (aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
 | |
|                        (aTag >> 8) & 0xff, aTag & 0xff);
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetVariationAxes(
 | |
|     nsTArray<InspectorVariationAxis>& aResult, ErrorResult& aRV) {
 | |
|   if (!mFontEntry->HasVariations()) {
 | |
|     return;
 | |
|   }
 | |
|   AutoTArray<gfxFontVariationAxis, 4> axes;
 | |
|   mFontEntry->GetVariationAxes(axes);
 | |
|   MOZ_ASSERT(!axes.IsEmpty());
 | |
|   if (!aResult.SetCapacity(axes.Length(), mozilla::fallible)) {
 | |
|     aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
|   for (auto a : axes) {
 | |
|     InspectorVariationAxis& axis = *aResult.AppendElement();
 | |
|     AppendTagAsASCII(axis.mTag, a.mTag);
 | |
|     axis.mName.Append(NS_ConvertUTF8toUTF16(a.mName));
 | |
|     axis.mMinValue = a.mMinValue;
 | |
|     axis.mMaxValue = a.mMaxValue;
 | |
|     axis.mDefaultValue = a.mDefaultValue;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetVariationInstances(
 | |
|     nsTArray<InspectorVariationInstance>& aResult, ErrorResult& aRV) {
 | |
|   if (!mFontEntry->HasVariations()) {
 | |
|     return;
 | |
|   }
 | |
|   AutoTArray<gfxFontVariationInstance, 16> instances;
 | |
|   mFontEntry->GetVariationInstances(instances);
 | |
|   if (!aResult.SetCapacity(instances.Length(), mozilla::fallible)) {
 | |
|     aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
|   for (auto i : instances) {
 | |
|     InspectorVariationInstance& inst = *aResult.AppendElement();
 | |
|     inst.mName.Append(NS_ConvertUTF8toUTF16(i.mName));
 | |
|     // inst.mValues is a webidl sequence<>, which is a fallible array,
 | |
|     // so we are required to use fallible SetCapacity and AppendElement calls,
 | |
|     // and check the result. In practice we don't expect failure here; the
 | |
|     // list of values cannot get huge because of limits in the font format.
 | |
|     if (!inst.mValues.SetCapacity(i.mValues.Length(), mozilla::fallible)) {
 | |
|       aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|       return;
 | |
|     }
 | |
|     for (auto v : i.mValues) {
 | |
|       InspectorVariationValue value;
 | |
|       AppendTagAsASCII(value.mAxis, v.mAxis);
 | |
|       value.mValue = v.mValue;
 | |
|       // This won't fail, because of SetCapacity above.
 | |
|       Unused << inst.mValues.AppendElement(value, mozilla::fallible);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetFeatures(nsTArray<InspectorFontFeature>& aResult,
 | |
|                                     ErrorResult& aRV) {
 | |
|   AutoTArray<gfxFontFeatureInfo, 64> features;
 | |
|   mFontEntry->GetFeatureInfo(features);
 | |
|   if (features.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
|   if (!aResult.SetCapacity(features.Length(), mozilla::fallible)) {
 | |
|     aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
|   for (auto& f : features) {
 | |
|     InspectorFontFeature& feat = *aResult.AppendElement();
 | |
|     AppendTagAsASCII(feat.mTag, f.mTag);
 | |
|     AppendTagAsASCII(feat.mScript, f.mScript);
 | |
|     AppendTagAsASCII(feat.mLanguageSystem, f.mLangSys);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::GetRanges(nsTArray<RefPtr<nsRange>>& aResult) {
 | |
|   aResult = mRanges;
 | |
| }
 | |
| 
 | |
| void InspectorFontFace::AddRange(nsRange* aRange) {
 | |
|   mRanges.AppendElement(aRange);
 | |
| }
 | |
| 
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 |