diff options
Diffstat (limited to 'layout/inspector/InspectorFontFace.cpp')
-rw-r--r-- | layout/inspector/InspectorFontFace.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/layout/inspector/InspectorFontFace.cpp b/layout/inspector/InspectorFontFace.cpp new file mode 100644 index 0000000000..0127b14282 --- /dev/null +++ b/layout/inspector/InspectorFontFace.cpp @@ -0,0 +1,297 @@ +/* -*- 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 { + +InspectorFontFace::InspectorFontFace(gfxFontEntry* aFontEntry, + gfxFontGroup* aFontGroup, + FontMatchType aMatchType) + : mFontEntry(aFontEntry), mFontGroup(aFontGroup), mMatchType(aMatchType) { + MOZ_COUNT_CTOR(InspectorFontFace); +} + +InspectorFontFace::~InspectorFontFace() { MOZ_COUNT_DTOR(InspectorFontFace); } + +bool InspectorFontFace::FromFontGroup() { + return bool(mMatchType.kind & FontMatchType::Kind::kFontGroup); +} + +bool InspectorFontFace::FromLanguagePrefs() { + return bool(mMatchType.kind & FontMatchType::Kind::kPrefsFallback); +} + +bool InspectorFontFace::FromSystemFallback() { + return bool(mMatchType.kind & FontMatchType::Kind::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) { + if (mMatchType.generic != StyleGenericFontFamily::None) { + aName.AssignASCII(gfxPlatformFontList::GetGenericName(mMatchType.generic)); + } 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 (const 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 (const 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.Clone(); +} + +void InspectorFontFace::AddRange(nsRange* aRange) { + mRanges.AppendElement(aRange); +} + +} // namespace dom +} // namespace mozilla |