OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are met: | 5 * modification, are permitted provided that the following conditions are met: |
6 * | 6 * |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 13 matching lines...) Expand all Loading... |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/css/FontFaceSet.h" | 27 #include "core/css/FontFaceSet.h" |
28 | 28 |
29 #include "RuntimeEnabledFeatures.h" | 29 #include "RuntimeEnabledFeatures.h" |
30 #include "bindings/v8/Dictionary.h" | 30 #include "bindings/v8/Dictionary.h" |
31 #include "bindings/v8/ScriptPromiseResolver.h" | 31 #include "bindings/v8/ScriptPromiseResolver.h" |
32 #include "bindings/v8/ScriptScope.h" | 32 #include "bindings/v8/ScriptScope.h" |
33 #include "bindings/v8/ScriptState.h" | 33 #include "bindings/v8/ScriptState.h" |
| 34 #include "core/css/CSSFontFace.h" |
34 #include "core/css/CSSFontFaceLoadEvent.h" | 35 #include "core/css/CSSFontFaceLoadEvent.h" |
35 #include "core/css/CSSFontFaceSource.h" | 36 #include "core/css/CSSFontFaceSource.h" |
36 #include "core/css/CSSFontSelector.h" | 37 #include "core/css/CSSFontSelector.h" |
37 #include "core/css/parser/BisonCSSParser.h" | 38 #include "core/css/parser/BisonCSSParser.h" |
38 #include "core/css/CSSSegmentedFontFace.h" | 39 #include "core/css/CSSSegmentedFontFace.h" |
| 40 #include "core/css/CSSSegmentedFontFaceCache.h" |
39 #include "core/css/StylePropertySet.h" | 41 #include "core/css/StylePropertySet.h" |
40 #include "core/css/resolver/StyleResolver.h" | 42 #include "core/css/resolver/StyleResolver.h" |
41 #include "core/dom/Document.h" | 43 #include "core/dom/Document.h" |
42 #include "core/frame/Frame.h" | 44 #include "core/frame/Frame.h" |
43 #include "core/frame/FrameView.h" | 45 #include "core/frame/FrameView.h" |
44 #include "public/platform/Platform.h" | 46 #include "public/platform/Platform.h" |
45 | 47 |
46 namespace WebCore { | 48 namespace WebCore { |
47 | 49 |
48 static const int defaultFontSize = 10; | 50 static const int defaultFontSize = 10; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 | 113 |
112 private: | 114 private: |
113 FontsReadyPromiseResolver(ScriptPromise promise, ExecutionContext* context) | 115 FontsReadyPromiseResolver(ScriptPromise promise, ExecutionContext* context) |
114 : m_scriptState(ScriptState::current()) | 116 : m_scriptState(ScriptState::current()) |
115 , m_resolver(ScriptPromiseResolver::create(promise, context)) | 117 , m_resolver(ScriptPromiseResolver::create(promise, context)) |
116 { } | 118 { } |
117 ScriptState* m_scriptState; | 119 ScriptState* m_scriptState; |
118 RefPtr<ScriptPromiseResolver> m_resolver; | 120 RefPtr<ScriptPromiseResolver> m_resolver; |
119 }; | 121 }; |
120 | 122 |
| 123 static void flushPendingStyleChanges(Document* document) |
| 124 { |
| 125 document->ensureStyleResolver(); |
| 126 } |
| 127 |
121 FontFaceSet::FontFaceSet(Document* document) | 128 FontFaceSet::FontFaceSet(Document* document) |
122 : ActiveDOMObject(document) | 129 : ActiveDOMObject(document) |
123 , m_loadingCount(0) | 130 , m_loadingCount(0) |
124 , m_shouldFireLoadingEvent(false) | 131 , m_shouldFireLoadingEvent(false) |
125 , m_asyncRunner(this, &FontFaceSet::handlePendingEventsAndPromises) | 132 , m_asyncRunner(this, &FontFaceSet::handlePendingEventsAndPromises) |
126 { | 133 { |
127 suspendIfNeeded(); | 134 suspendIfNeeded(); |
128 } | 135 } |
129 | 136 |
130 FontFaceSet::~FontFaceSet() | 137 FontFaceSet::~FontFaceSet() |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 | 247 |
241 ScriptPromise FontFaceSet::ready() | 248 ScriptPromise FontFaceSet::ready() |
242 { | 249 { |
243 ScriptPromise promise = ScriptPromise::createPending(executionContext()); | 250 ScriptPromise promise = ScriptPromise::createPending(executionContext()); |
244 OwnPtr<FontsReadyPromiseResolver> resolver = FontsReadyPromiseResolver::crea
te(promise, executionContext()); | 251 OwnPtr<FontsReadyPromiseResolver> resolver = FontsReadyPromiseResolver::crea
te(promise, executionContext()); |
245 m_readyResolvers.append(resolver.release()); | 252 m_readyResolvers.append(resolver.release()); |
246 handlePendingEventsAndPromisesSoon(); | 253 handlePendingEventsAndPromisesSoon(); |
247 return promise; | 254 return promise; |
248 } | 255 } |
249 | 256 |
| 257 bool FontFaceSet::has(FontFace* fontFace, ExceptionState& exceptionState) const |
| 258 { |
| 259 if (!fontFace) { |
| 260 exceptionState.throwTypeError("The argument is not a FontFace."); |
| 261 return false; |
| 262 } |
| 263 flushPendingStyleChanges(document()); |
| 264 return document()->styleEngine()->fontSelector()->cssSegmentedFontFaceCache(
)->cssFontFaceList().contains(fontFace->cssFontFace()); |
| 265 } |
| 266 |
| 267 void FontFaceSet::forEach(PassOwnPtr<FontFaceSetForEachCallback> callback, Scrip
tValue& thisArg) const |
| 268 { |
| 269 forEachInternal(callback, &thisArg); |
| 270 } |
| 271 |
| 272 void FontFaceSet::forEach(PassOwnPtr<FontFaceSetForEachCallback> callback) const |
| 273 { |
| 274 forEachInternal(callback, 0); |
| 275 } |
| 276 |
| 277 void FontFaceSet::forEachInternal(PassOwnPtr<FontFaceSetForEachCallback> callbac
k, ScriptValue* thisArg) const |
| 278 { |
| 279 flushPendingStyleChanges(document()); |
| 280 const ListHashSet<RefPtr<CSSFontFace> >& faces = document()->styleEngine()->
fontSelector()->cssSegmentedFontFaceCache()->cssFontFaceList(); |
| 281 Vector<RefPtr<FontFace> > fontFaces; |
| 282 fontFaces.reserveInitialCapacity(faces.size()); |
| 283 for (ListHashSet<RefPtr<CSSFontFace> >::const_iterator it = faces.begin(); i
t != faces.end(); ++it) |
| 284 fontFaces.append((*it)->fontFace()); |
| 285 |
| 286 for (size_t i = 0; i < fontFaces.size(); ++i) { |
| 287 FontFace* face = fontFaces[i].get(); |
| 288 if (thisArg) |
| 289 callback->handleItem(*thisArg, face, face, const_cast<FontFaceSet*>(
this)); |
| 290 else |
| 291 callback->handleItem(face, face, const_cast<FontFaceSet*>(this)); |
| 292 } |
| 293 } |
| 294 |
| 295 unsigned long FontFaceSet::size() const |
| 296 { |
| 297 flushPendingStyleChanges(document()); |
| 298 return document()->styleEngine()->fontSelector()->cssSegmentedFontFaceCache(
)->cssFontFaceList().size(); |
| 299 } |
| 300 |
250 void FontFaceSet::fireDoneEventIfPossible() | 301 void FontFaceSet::fireDoneEventIfPossible() |
251 { | 302 { |
252 if (m_shouldFireLoadingEvent) | 303 if (m_shouldFireLoadingEvent) |
253 return; | 304 return; |
254 if (m_loadingCount || (!hasLoadedFonts() && m_readyResolvers.isEmpty())) | 305 if (m_loadingCount || (!hasLoadedFonts() && m_readyResolvers.isEmpty())) |
255 return; | 306 return; |
256 | 307 |
257 // If the layout was invalidated in between when we thought layout | 308 // If the layout was invalidated in between when we thought layout |
258 // was updated and when we're ready to fire the event, just wait | 309 // was updated and when we're ready to fire the event, just wait |
259 // until after the next layout before firing events. | 310 // until after the next layout before firing events. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 Vector<RefPtr<FontFace> > FontFaceSet::match(const String& fontString, const Str
ing& text, ExceptionState& exceptionState) | 343 Vector<RefPtr<FontFace> > FontFaceSet::match(const String& fontString, const Str
ing& text, ExceptionState& exceptionState) |
293 { | 344 { |
294 Vector<RefPtr<FontFace> > matchedFonts; | 345 Vector<RefPtr<FontFace> > matchedFonts; |
295 | 346 |
296 Font font; | 347 Font font; |
297 if (!resolveFontStyle(fontString, font)) { | 348 if (!resolveFontStyle(fontString, font)) { |
298 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 349 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
299 return matchedFonts; | 350 return matchedFonts; |
300 } | 351 } |
301 | 352 |
| 353 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
302 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 354 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
303 CSSSegmentedFontFace* face = document()->styleEngine()->fontSelector()->
getFontFace(font.fontDescription(), f->family()); | 355 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
304 if (face) | 356 if (face) |
305 matchedFonts.append(face->fontFaces(nullToSpace(text))); | 357 matchedFonts.append(face->fontFaces(nullToSpace(text))); |
306 } | 358 } |
307 return matchedFonts; | 359 return matchedFonts; |
308 } | 360 } |
309 | 361 |
310 ScriptPromise FontFaceSet::load(const String& fontString, const String& text, Ex
ceptionState& exceptionState) | 362 ScriptPromise FontFaceSet::load(const String& fontString, const String& text, Ex
ceptionState& exceptionState) |
311 { | 363 { |
312 Font font; | 364 Font font; |
313 if (!resolveFontStyle(fontString, font)) { | 365 if (!resolveFontStyle(fontString, font)) { |
314 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 366 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
315 return ScriptPromise(); | 367 return ScriptPromise(); |
316 } | 368 } |
317 | 369 |
318 Document* d = document(); | 370 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
319 ScriptPromise promise = ScriptPromise::createPending(executionContext()); | 371 ScriptPromise promise = ScriptPromise::createPending(executionContext()); |
320 RefPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(f
ont.family(), promise, executionContext()); | 372 RefPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(f
ont.family(), promise, executionContext()); |
321 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 373 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
322 CSSSegmentedFontFace* face = d->styleEngine()->fontSelector()->getFontFa
ce(font.fontDescription(), f->family()); | 374 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
323 if (!face) { | 375 if (!face) { |
324 resolver->error(); | 376 resolver->error(); |
325 continue; | 377 continue; |
326 } | 378 } |
327 face->loadFont(font.fontDescription(), nullToSpace(text), resolver); | 379 face->loadFont(font.fontDescription(), nullToSpace(text), resolver); |
328 } | 380 } |
329 return promise; | 381 return promise; |
330 } | 382 } |
331 | 383 |
332 bool FontFaceSet::check(const String& fontString, const String& text, ExceptionS
tate& exceptionState) | 384 bool FontFaceSet::check(const String& fontString, const String& text, ExceptionS
tate& exceptionState) |
333 { | 385 { |
334 Font font; | 386 Font font; |
335 if (!resolveFontStyle(fontString, font)) { | 387 if (!resolveFontStyle(fontString, font)) { |
336 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 388 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
337 return false; | 389 return false; |
338 } | 390 } |
339 | 391 |
| 392 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
340 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 393 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
341 CSSSegmentedFontFace* face = document()->styleEngine()->fontSelector()->
getFontFace(font.fontDescription(), f->family()); | 394 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
342 if (!face || !face->checkFont(nullToSpace(text))) | 395 if (!face || !face->checkFont(nullToSpace(text))) |
343 return false; | 396 return false; |
344 } | 397 } |
345 return true; | 398 return true; |
346 } | 399 } |
347 | 400 |
348 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) | 401 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) |
349 { | 402 { |
350 if (fontString.isEmpty()) | 403 if (fontString.isEmpty()) |
351 return false; | 404 return false; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 } | 469 } |
417 | 470 |
418 void FontFaceSet::didLayout(Document* document) | 471 void FontFaceSet::didLayout(Document* document) |
419 { | 472 { |
420 if (FontFaceSet* fonts = static_cast<FontFaceSet*>(SupplementType::from(docu
ment, supplementName()))) | 473 if (FontFaceSet* fonts = static_cast<FontFaceSet*>(SupplementType::from(docu
ment, supplementName()))) |
421 fonts->didLayout(); | 474 fonts->didLayout(); |
422 } | 475 } |
423 | 476 |
424 | 477 |
425 } // namespace WebCore | 478 } // namespace WebCore |
OLD | NEW |