Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: sky/engine/core/css/FontFaceSet.cpp

Issue 1223843003: Remove support for loading remote font faces (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/core/css/FontFaceSet.h ('k') | sky/engine/core/css/FontFaceSet.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
23 * DAMAGE.
24 */
25
26 #include "sky/engine/core/css/FontFaceSet.h"
27
28 #include "sky/engine/core/css/CSSFontSelector.h"
29 #include "sky/engine/core/css/CSSSegmentedFontFace.h"
30 #include "sky/engine/core/css/FontFaceCache.h"
31 #include "sky/engine/core/css/FontFaceSetLoadEvent.h"
32 #include "sky/engine/core/css/StylePropertySet.h"
33 #include "sky/engine/core/css/parser/BisonCSSParser.h"
34 #include "sky/engine/core/css/resolver/StyleResolver.h"
35 #include "sky/engine/core/dom/Document.h"
36 #include "sky/engine/core/dom/StyleEngine.h"
37 #include "sky/engine/core/frame/FrameView.h"
38 #include "sky/engine/core/frame/LocalFrame.h"
39 #include "sky/engine/core/rendering/style/RenderStyle.h"
40 #include "sky/engine/core/rendering/style/StyleInheritedData.h"
41 #include "sky/engine/public/platform/Platform.h"
42
43 namespace blink {
44
45 static const int defaultFontSize = 10;
46 static const char defaultFontFamily[] = "sans-serif";
47
48 FontFaceSet::FontFaceSet(Document& document)
49 : ActiveDOMObject(&document)
50 , m_shouldFireLoadingEvent(false)
51 , m_asyncRunner(this, &FontFaceSet::handlePendingEventsAndPromises)
52 {
53 suspendIfNeeded();
54 }
55
56 FontFaceSet::~FontFaceSet()
57 {
58 }
59
60 Document* FontFaceSet::document() const
61 {
62 return toDocument(executionContext());
63 }
64
65 bool FontFaceSet::inActiveDocumentContext() const
66 {
67 ExecutionContext* context = executionContext();
68 return context && toDocument(context)->isActive();
69 }
70
71 void FontFaceSet::addFontFacesToFontFaceCache(FontFaceCache* fontFaceCache, CSSF ontSelector* fontSelector)
72 {
73 for (ListHashSet<RefPtr<FontFace> >::iterator it = m_nonCSSConnectedFaces.be gin(); it != m_nonCSSConnectedFaces.end(); ++it)
74 fontFaceCache->addFontFace(fontSelector, *it, false);
75 }
76
77 const AtomicString& FontFaceSet::interfaceName() const
78 {
79 return EventTargetNames::FontFaceSet;
80 }
81
82 ExecutionContext* FontFaceSet::executionContext() const
83 {
84 return ActiveDOMObject::executionContext();
85 }
86
87 AtomicString FontFaceSet::status() const
88 {
89 DEFINE_STATIC_LOCAL(AtomicString, loading, ("loading", AtomicString::Constru ctFromLiteral));
90 DEFINE_STATIC_LOCAL(AtomicString, loaded, ("loaded", AtomicString::Construct FromLiteral));
91 return (!m_loadingFonts.isEmpty() || hasLoadedFonts()) ? loading : loaded;
92 }
93
94 void FontFaceSet::handlePendingEventsAndPromisesSoon()
95 {
96 // m_asyncRunner will be automatically stopped on destruction.
97 m_asyncRunner.runAsync();
98 }
99
100 void FontFaceSet::didLayout()
101 {
102 if (m_loadingFonts.isEmpty())
103 m_histogram.record();
104 if (!m_loadingFonts.isEmpty() || !hasLoadedFonts())
105 return;
106 handlePendingEventsAndPromisesSoon();
107 }
108
109 void FontFaceSet::handlePendingEventsAndPromises()
110 {
111 fireLoadingEvent();
112 fireDoneEventIfPossible();
113 }
114
115 void FontFaceSet::fireLoadingEvent()
116 {
117 if (m_shouldFireLoadingEvent) {
118 m_shouldFireLoadingEvent = false;
119 dispatchEvent(FontFaceSetLoadEvent::createForFontFaces(EventTypeNames::l oading));
120 }
121 }
122
123 void FontFaceSet::suspend()
124 {
125 m_asyncRunner.suspend();
126 }
127
128 void FontFaceSet::resume()
129 {
130 m_asyncRunner.resume();
131 }
132
133 void FontFaceSet::stop()
134 {
135 m_asyncRunner.stop();
136 }
137
138 void FontFaceSet::beginFontLoading(FontFace* fontFace)
139 {
140 m_histogram.incrementCount();
141 addToLoadingFonts(fontFace);
142 }
143
144 void FontFaceSet::fontLoaded(FontFace* fontFace)
145 {
146 m_histogram.updateStatus(fontFace);
147 m_loadedFonts.append(fontFace);
148 removeFromLoadingFonts(fontFace);
149 }
150
151 void FontFaceSet::loadError(FontFace* fontFace)
152 {
153 m_histogram.updateStatus(fontFace);
154 m_failedFonts.append(fontFace);
155 removeFromLoadingFonts(fontFace);
156 }
157
158 void FontFaceSet::addToLoadingFonts(PassRefPtr<FontFace> fontFace)
159 {
160 if (m_loadingFonts.isEmpty() && !hasLoadedFonts()) {
161 m_shouldFireLoadingEvent = true;
162 handlePendingEventsAndPromisesSoon();
163 }
164 m_loadingFonts.add(fontFace);
165 }
166
167 void FontFaceSet::removeFromLoadingFonts(PassRefPtr<FontFace> fontFace)
168 {
169 m_loadingFonts.remove(fontFace);
170 if (m_loadingFonts.isEmpty())
171 handlePendingEventsAndPromisesSoon();
172 }
173
174 void FontFaceSet::add(FontFace* fontFace, ExceptionState& exceptionState)
175 {
176 if (!inActiveDocumentContext())
177 return;
178 if (!fontFace) {
179 exceptionState.ThrowTypeError("The argument is not a FontFace.");
180 return;
181 }
182 if (m_nonCSSConnectedFaces.contains(fontFace))
183 return;
184 if (isCSSConnectedFontFace(fontFace)) {
185 exceptionState.ThrowDOMException(InvalidModificationError, "Cannot add a CSS-connected FontFace.");
186 return;
187 }
188 CSSFontSelector* fontSelector = document()->styleEngine()->fontSelector();
189 m_nonCSSConnectedFaces.add(fontFace);
190 fontSelector->fontFaceCache()->addFontFace(fontSelector, fontFace, false);
191 if (fontFace->loadStatus() == FontFace::Loading)
192 addToLoadingFonts(fontFace);
193 fontSelector->fontFaceInvalidated();
194 }
195
196 void FontFaceSet::clear()
197 {
198 if (!inActiveDocumentContext() || m_nonCSSConnectedFaces.isEmpty())
199 return;
200 CSSFontSelector* fontSelector = document()->styleEngine()->fontSelector();
201 FontFaceCache* fontFaceCache = fontSelector->fontFaceCache();
202 for (ListHashSet<RefPtr<FontFace> >::iterator it = m_nonCSSConnectedFaces.be gin(); it != m_nonCSSConnectedFaces.end(); ++it) {
203 fontFaceCache->removeFontFace(it->get(), false);
204 if ((*it)->loadStatus() == FontFace::Loading)
205 removeFromLoadingFonts(*it);
206 }
207 m_nonCSSConnectedFaces.clear();
208 fontSelector->fontFaceInvalidated();
209 }
210
211 bool FontFaceSet::remove(FontFace* fontFace, ExceptionState& exceptionState)
212 {
213 if (!inActiveDocumentContext())
214 return false;
215 if (!fontFace) {
216 exceptionState.ThrowTypeError("The argument is not a FontFace.");
217 return false;
218 }
219 ListHashSet<RefPtr<FontFace> >::iterator it = m_nonCSSConnectedFaces.find(fo ntFace);
220 if (it != m_nonCSSConnectedFaces.end()) {
221 m_nonCSSConnectedFaces.remove(it);
222 CSSFontSelector* fontSelector = document()->styleEngine()->fontSelector( );
223 fontSelector->fontFaceCache()->removeFontFace(fontFace, false);
224 if (fontFace->loadStatus() == FontFace::Loading)
225 removeFromLoadingFonts(fontFace);
226 fontSelector->fontFaceInvalidated();
227 return true;
228 }
229 if (isCSSConnectedFontFace(fontFace))
230 exceptionState.ThrowDOMException(InvalidModificationError, "Cannot delet e a CSS-connected FontFace.");
231 return false;
232 }
233
234 bool FontFaceSet::has(FontFace* fontFace, ExceptionState& exceptionState) const
235 {
236 if (!inActiveDocumentContext())
237 return false;
238 if (!fontFace) {
239 exceptionState.ThrowTypeError("The argument is not a FontFace.");
240 return false;
241 }
242 return m_nonCSSConnectedFaces.contains(fontFace) || isCSSConnectedFontFace(f ontFace);
243 }
244
245 const ListHashSet<RefPtr<FontFace> >& FontFaceSet::cssConnectedFontFaceList() co nst
246 {
247 Document* d = document();
248 return d->styleEngine()->fontSelector()->fontFaceCache()->cssConnectedFontFa ces();
249 }
250
251 bool FontFaceSet::isCSSConnectedFontFace(FontFace* fontFace) const
252 {
253 return cssConnectedFontFaceList().contains(fontFace);
254 }
255
256 unsigned long FontFaceSet::size() const
257 {
258 if (!inActiveDocumentContext())
259 return m_nonCSSConnectedFaces.size();
260 return cssConnectedFontFaceList().size() + m_nonCSSConnectedFaces.size();
261 }
262
263 void FontFaceSet::fireDoneEventIfPossible()
264 {
265 if (m_shouldFireLoadingEvent)
266 return;
267 if (!m_loadingFonts.isEmpty() || !hasLoadedFonts())
268 return;
269
270 // If the layout was invalidated in between when we thought layout
271 // was updated and when we're ready to fire the event, just wait
272 // until after the next layout before firing events.
273 Document* d = document();
274 if (!d->view() || d->view()->needsLayout())
275 return;
276
277 if (hasLoadedFonts()) {
278 RefPtr<FontFaceSetLoadEvent> doneEvent = nullptr;
279 RefPtr<FontFaceSetLoadEvent> errorEvent = nullptr;
280 doneEvent = FontFaceSetLoadEvent::createForFontFaces(EventTypeNames::loa dingdone, m_loadedFonts);
281 m_loadedFonts.clear();
282 if (!m_failedFonts.isEmpty()) {
283 errorEvent = FontFaceSetLoadEvent::createForFontFaces(EventTypeNames ::loadingerror, m_failedFonts);
284 m_failedFonts.clear();
285 }
286 dispatchEvent(doneEvent);
287 if (errorEvent)
288 dispatchEvent(errorEvent);
289 }
290 }
291
292 static const String& nullToSpace(const String& s)
293 {
294 DEFINE_STATIC_LOCAL(String, space, (" "));
295 return s.isNull() ? space : s;
296 }
297
298 bool FontFaceSet::check(const String& fontString, const String& text, ExceptionS tate& exceptionState)
299 {
300 if (!inActiveDocumentContext())
301 return false;
302
303 Font font;
304 if (!resolveFontStyle(fontString, font)) {
305 exceptionState.ThrowDOMException(SyntaxError, "Could not resolve '" + fo ntString + "' as a font.");
306 return false;
307 }
308
309 CSSFontSelector* fontSelector = document()->styleEngine()->fontSelector();
310 FontFaceCache* fontFaceCache = fontSelector->fontFaceCache();
311
312 bool hasLoadedFaces = false;
313 for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next( )) {
314 CSSSegmentedFontFace* face = fontFaceCache->get(font.fontDescription(), f->family());
315 if (face) {
316 if (!face->checkFont(nullToSpace(text)))
317 return false;
318 hasLoadedFaces = true;
319 }
320 }
321 if (hasLoadedFaces)
322 return true;
323 for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next( )) {
324 if (fontSelector->isPlatformFontAvailable(font.fontDescription(), f->fam ily()))
325 return true;
326 }
327 return false;
328 }
329
330 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font)
331 {
332 if (fontString.isEmpty())
333 return false;
334
335 // Interpret fontString in the same way as the 'font' attribute of CanvasRen deringContext2D.
336 RefPtr<MutableStylePropertySet> parsedStyle = MutableStylePropertySet::creat e();
337 BisonCSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, H TMLStandardMode, 0);
338 if (parsedStyle->isEmpty())
339 return false;
340
341 String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont);
342 if (fontValue == "inherit" || fontValue == "initial")
343 return false;
344
345 RefPtr<RenderStyle> style = RenderStyle::create();
346
347 FontFamily fontFamily;
348 fontFamily.setFamily(defaultFontFamily);
349
350 FontDescription defaultFontDescription;
351 defaultFontDescription.setFamily(fontFamily);
352 defaultFontDescription.setSpecifiedSize(defaultFontSize);
353 defaultFontDescription.setComputedSize(defaultFontSize);
354
355 style->setFontDescription(defaultFontDescription);
356
357 style->font().update(style->font().fontSelector());
358
359 // Now map the font property longhands into the style.
360 CSSPropertyValue properties[] = {
361 CSSPropertyValue(CSSPropertyFontFamily, *parsedStyle),
362 CSSPropertyValue(CSSPropertyFontStretch, *parsedStyle),
363 CSSPropertyValue(CSSPropertyFontStyle, *parsedStyle),
364 CSSPropertyValue(CSSPropertyFontVariant, *parsedStyle),
365 CSSPropertyValue(CSSPropertyFontWeight, *parsedStyle),
366 CSSPropertyValue(CSSPropertyFontSize, *parsedStyle),
367 CSSPropertyValue(CSSPropertyLineHeight, *parsedStyle),
368 };
369 StyleResolver& styleResolver = document()->styleResolver();
370 styleResolver.applyPropertiesToStyle(properties, WTF_ARRAY_LENGTH(properties ), style.get());
371
372 font = style->font();
373 font.update(document()->styleEngine()->fontSelector());
374 return true;
375 }
376
377 void FontFaceSet::FontLoadHistogram::updateStatus(FontFace* fontFace)
378 {
379 if (m_status == Reported)
380 return;
381 if (fontFace->hadBlankText())
382 m_status = HadBlankText;
383 else if (m_status == NoWebFonts)
384 m_status = DidNotHaveBlankText;
385 }
386
387 void FontFaceSet::FontLoadHistogram::record()
388 {
389 if (!m_recorded) {
390 m_recorded = true;
391 blink::Platform::current()->histogramCustomCounts("WebFont.WebFontsInPag e", m_count, 1, 100, 50);
392 }
393 if (m_status == HadBlankText || m_status == DidNotHaveBlankText) {
394 blink::Platform::current()->histogramEnumeration("WebFont.HadBlankText", m_status == HadBlankText ? 1 : 0, 2);
395 m_status = Reported;
396 }
397 }
398
399 static const char* supplementName()
400 {
401 return "FontFaceSet";
402 }
403
404 PassRefPtr<FontFaceSet> FontFaceSet::from(Document& document)
405 {
406 RefPtr<FontFaceSet> fonts = static_cast<FontFaceSet*>(SupplementType::from(d ocument, supplementName()));
407 if (!fonts) {
408 fonts = FontFaceSet::create(document);
409 SupplementType::provideTo(document, supplementName(), fonts);
410 }
411
412 return fonts.release();
413 }
414
415 void FontFaceSet::didLayout(Document& document)
416 {
417 if (FontFaceSet* fonts = static_cast<FontFaceSet*>(SupplementType::from(docu ment, supplementName())))
418 fonts->didLayout();
419 }
420
421 } // namespace blink
OLDNEW
« no previous file with comments | « sky/engine/core/css/FontFaceSet.h ('k') | sky/engine/core/css/FontFaceSet.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698