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