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 "gfxPlatformFontList.h"
10 #include "gfxTextRun.h"
11 #include "gfxUserFontSet.h"
12 #include "nsFontFaceLoader.h"
13 #include "mozilla/gfx/2D.h"
14 #include "brotli/decode.h"
15 #include "zlib.h"
16 #include "mozilla/dom/CSSFontFaceRule.h"
17 #include "mozilla/dom/FontFaceSet.h"
18 #include "mozilla/ServoBindings.h"
19 #include "mozilla/Unused.h"
20
21 namespace mozilla {
22 namespace dom {
23
InspectorFontFace(gfxFontEntry * aFontEntry,gfxFontGroup * aFontGroup,FontMatchType aMatchType)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
~InspectorFontFace()31 InspectorFontFace::~InspectorFontFace() { MOZ_COUNT_DTOR(InspectorFontFace); }
32
FromFontGroup()33 bool InspectorFontFace::FromFontGroup() {
34 return bool(mMatchType.kind & FontMatchType::Kind::kFontGroup);
35 }
36
FromLanguagePrefs()37 bool InspectorFontFace::FromLanguagePrefs() {
38 return bool(mMatchType.kind & FontMatchType::Kind::kPrefsFallback);
39 }
40
FromSystemFallback()41 bool InspectorFontFace::FromSystemFallback() {
42 return bool(mMatchType.kind & FontMatchType::Kind::kSystemFallback);
43 }
44
GetName(nsAString & aName)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
GetCSSFamilyName(nsAString & aCSSFamilyName)54 void InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) {
55 aCSSFamilyName.Append(NS_ConvertUTF8toUTF16(mFontEntry->FamilyName()));
56 }
57
GetCSSGeneric(nsAString & aName)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
GetRule()66 CSSFontFaceRule* InspectorFontFace::GetRule() {
67 if (!mRule) {
68 // check whether this font entry is associated with an @font-face rule
69 // in the relevant font group's user font set
70 RawServoFontFaceRule* rule = nullptr;
71 if (mFontEntry->IsUserFont()) {
72 FontFaceSet::UserFontSet* fontSet =
73 static_cast<FontFaceSet::UserFontSet*>(mFontGroup->GetUserFontSet());
74 if (fontSet) {
75 FontFaceSet* fontFaceSet = fontSet->GetFontFaceSet();
76 if (fontFaceSet) {
77 rule = fontFaceSet->FindRuleForEntry(mFontEntry);
78 }
79 }
80 }
81 if (rule) {
82 // XXX It would be better if we can share this with CSSOM tree,
83 // but that may require us to create another map, which is not
84 // great either. As far as they would use the same backend, and
85 // we don't really support mutating @font-face rule via CSSOM,
86 // it's probably fine for now.
87 uint32_t line, column;
88 Servo_FontFaceRule_GetSourceLocation(rule, &line, &column);
89 mRule =
90 new CSSFontFaceRule(do_AddRef(rule), nullptr, nullptr, line, column);
91 }
92 }
93 return mRule;
94 }
95
SrcIndex()96 int32_t InspectorFontFace::SrcIndex() {
97 if (mFontEntry->IsUserFont()) {
98 NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
99 return mFontEntry->mUserFontData->mSrcIndex;
100 }
101
102 return -1;
103 }
104
GetURI(nsAString & aURI)105 void InspectorFontFace::GetURI(nsAString& aURI) {
106 aURI.Truncate();
107 if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
108 NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
109 if (mFontEntry->mUserFontData->mURI) {
110 nsAutoCString spec;
111 mFontEntry->mUserFontData->mURI->GetSpec(spec);
112 AppendUTF8toUTF16(spec, aURI);
113 }
114 }
115 }
116
GetLocalName(nsAString & aLocalName)117 void InspectorFontFace::GetLocalName(nsAString& aLocalName) {
118 aLocalName.Truncate();
119 if (mFontEntry->IsLocalUserFont()) {
120 NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
121 aLocalName.Append(
122 NS_ConvertUTF8toUTF16(mFontEntry->mUserFontData->mLocalName));
123 }
124 }
125
AppendToFormat(nsAString & aResult,const char * aFormat)126 static void AppendToFormat(nsAString& aResult, const char* aFormat) {
127 if (!aResult.IsEmpty()) {
128 aResult.Append(',');
129 }
130 aResult.AppendASCII(aFormat);
131 }
132
GetFormat(nsAString & aFormat)133 void InspectorFontFace::GetFormat(nsAString& aFormat) {
134 aFormat.Truncate();
135 if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
136 NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
137 uint32_t formatFlags = mFontEntry->mUserFontData->mFormat;
138 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_OPENTYPE) {
139 AppendToFormat(aFormat, "opentype");
140 }
141 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE) {
142 AppendToFormat(aFormat, "truetype");
143 }
144 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT) {
145 AppendToFormat(aFormat, "truetype-aat");
146 }
147 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_EOT) {
148 AppendToFormat(aFormat, "embedded-opentype");
149 }
150 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_SVG) {
151 AppendToFormat(aFormat, "svg");
152 }
153 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF) {
154 AppendToFormat(aFormat, "woff");
155 }
156 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF2) {
157 AppendToFormat(aFormat, "woff2");
158 }
159 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_OPENTYPE_VARIATIONS) {
160 AppendToFormat(aFormat, "opentype-variations");
161 }
162 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_VARIATIONS) {
163 AppendToFormat(aFormat, "truetype-variations");
164 }
165 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF_VARIATIONS) {
166 AppendToFormat(aFormat, "woff-variations");
167 }
168 if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF2_VARIATIONS) {
169 AppendToFormat(aFormat, "woff2-variations");
170 }
171 }
172 }
173
GetMetadata(nsAString & aMetadata)174 void InspectorFontFace::GetMetadata(nsAString& aMetadata) {
175 aMetadata.Truncate();
176 if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
177 NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
178 const gfxUserFontData* userFontData = mFontEntry->mUserFontData.get();
179 if (userFontData->mMetadata.Length() && userFontData->mMetaOrigLen) {
180 nsAutoCString str;
181 str.SetLength(userFontData->mMetaOrigLen);
182 if (str.Length() == userFontData->mMetaOrigLen) {
183 switch (userFontData->mCompression) {
184 case gfxUserFontData::kZlibCompression: {
185 uLongf destLen = userFontData->mMetaOrigLen;
186 if (uncompress((Bytef*)(str.BeginWriting()), &destLen,
187 (const Bytef*)(userFontData->mMetadata.Elements()),
188 userFontData->mMetadata.Length()) == Z_OK &&
189 destLen == userFontData->mMetaOrigLen) {
190 AppendUTF8toUTF16(str, aMetadata);
191 }
192 } break;
193 case gfxUserFontData::kBrotliCompression: {
194 size_t decodedSize = userFontData->mMetaOrigLen;
195 if (BrotliDecoderDecompress(userFontData->mMetadata.Length(),
196 userFontData->mMetadata.Elements(),
197 &decodedSize,
198 (uint8_t*)str.BeginWriting()) == 1 &&
199 decodedSize == userFontData->mMetaOrigLen) {
200 AppendUTF8toUTF16(str, aMetadata);
201 }
202 } break;
203 }
204 }
205 }
206 }
207 }
208
209 // Append an OpenType tag to a string as a 4-ASCII-character code.
AppendTagAsASCII(nsAString & aString,uint32_t aTag)210 static void AppendTagAsASCII(nsAString& aString, uint32_t aTag) {
211 aString.AppendPrintf("%c%c%c%c", (aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
212 (aTag >> 8) & 0xff, aTag & 0xff);
213 }
214
GetVariationAxes(nsTArray<InspectorVariationAxis> & aResult,ErrorResult & aRV)215 void InspectorFontFace::GetVariationAxes(
216 nsTArray<InspectorVariationAxis>& aResult, ErrorResult& aRV) {
217 if (!mFontEntry->HasVariations()) {
218 return;
219 }
220 AutoTArray<gfxFontVariationAxis, 4> axes;
221 mFontEntry->GetVariationAxes(axes);
222 MOZ_ASSERT(!axes.IsEmpty());
223 if (!aResult.SetCapacity(axes.Length(), mozilla::fallible)) {
224 aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
225 return;
226 }
227 for (auto a : axes) {
228 InspectorVariationAxis& axis = *aResult.AppendElement();
229 AppendTagAsASCII(axis.mTag, a.mTag);
230 axis.mName.Append(NS_ConvertUTF8toUTF16(a.mName));
231 axis.mMinValue = a.mMinValue;
232 axis.mMaxValue = a.mMaxValue;
233 axis.mDefaultValue = a.mDefaultValue;
234 }
235 }
236
GetVariationInstances(nsTArray<InspectorVariationInstance> & aResult,ErrorResult & aRV)237 void InspectorFontFace::GetVariationInstances(
238 nsTArray<InspectorVariationInstance>& aResult, ErrorResult& aRV) {
239 if (!mFontEntry->HasVariations()) {
240 return;
241 }
242 AutoTArray<gfxFontVariationInstance, 16> instances;
243 mFontEntry->GetVariationInstances(instances);
244 if (!aResult.SetCapacity(instances.Length(), mozilla::fallible)) {
245 aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
246 return;
247 }
248 for (const auto& i : instances) {
249 InspectorVariationInstance& inst = *aResult.AppendElement();
250 inst.mName.Append(NS_ConvertUTF8toUTF16(i.mName));
251 // inst.mValues is a webidl sequence<>, which is a fallible array,
252 // so we are required to use fallible SetCapacity and AppendElement calls,
253 // and check the result. In practice we don't expect failure here; the
254 // list of values cannot get huge because of limits in the font format.
255 if (!inst.mValues.SetCapacity(i.mValues.Length(), mozilla::fallible)) {
256 aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
257 return;
258 }
259 for (const auto& v : i.mValues) {
260 InspectorVariationValue value;
261 AppendTagAsASCII(value.mAxis, v.mAxis);
262 value.mValue = v.mValue;
263 // This won't fail, because of SetCapacity above.
264 Unused << inst.mValues.AppendElement(value, mozilla::fallible);
265 }
266 }
267 }
268
GetFeatures(nsTArray<InspectorFontFeature> & aResult,ErrorResult & aRV)269 void InspectorFontFace::GetFeatures(nsTArray<InspectorFontFeature>& aResult,
270 ErrorResult& aRV) {
271 AutoTArray<gfxFontFeatureInfo, 64> features;
272 mFontEntry->GetFeatureInfo(features);
273 if (features.IsEmpty()) {
274 return;
275 }
276 if (!aResult.SetCapacity(features.Length(), mozilla::fallible)) {
277 aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
278 return;
279 }
280 for (auto& f : features) {
281 InspectorFontFeature& feat = *aResult.AppendElement();
282 AppendTagAsASCII(feat.mTag, f.mTag);
283 AppendTagAsASCII(feat.mScript, f.mScript);
284 AppendTagAsASCII(feat.mLanguageSystem, f.mLangSys);
285 }
286 }
287
GetRanges(nsTArray<RefPtr<nsRange>> & aResult)288 void InspectorFontFace::GetRanges(nsTArray<RefPtr<nsRange>>& aResult) {
289 aResult = mRanges.Clone();
290 }
291
AddRange(nsRange * aRange)292 void InspectorFontFace::AddRange(nsRange* aRange) {
293 mRanges.AppendElement(aRange);
294 }
295
296 } // namespace dom
297 } // namespace mozilla
298