| 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 if (thisArg) |
| 288 callback->handleItem(*thisArg, fontFaces[i].get(), const_cast<FontFa
ceSet*>(this)); |
| 289 else |
| 290 callback->handleItem(fontFaces[i].get(), const_cast<FontFaceSet*>(th
is)); |
| 291 } |
| 292 } |
| 293 |
| 294 unsigned long FontFaceSet::size() const |
| 295 { |
| 296 flushPendingStyleChanges(document()); |
| 297 return document()->styleEngine()->fontSelector()->cssSegmentedFontFaceCache(
)->cssFontFaceList().size(); |
| 298 } |
| 299 |
| 250 void FontFaceSet::fireDoneEventIfPossible() | 300 void FontFaceSet::fireDoneEventIfPossible() |
| 251 { | 301 { |
| 252 if (m_shouldFireLoadingEvent) | 302 if (m_shouldFireLoadingEvent) |
| 253 return; | 303 return; |
| 254 if (m_loadingCount || (!hasLoadedFonts() && m_readyResolvers.isEmpty())) | 304 if (m_loadingCount || (!hasLoadedFonts() && m_readyResolvers.isEmpty())) |
| 255 return; | 305 return; |
| 256 | 306 |
| 257 // If the layout was invalidated in between when we thought layout | 307 // 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 | 308 // was updated and when we're ready to fire the event, just wait |
| 259 // until after the next layout before firing events. | 309 // 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) | 342 Vector<RefPtr<FontFace> > FontFaceSet::match(const String& fontString, const Str
ing& text, ExceptionState& exceptionState) |
| 293 { | 343 { |
| 294 Vector<RefPtr<FontFace> > matchedFonts; | 344 Vector<RefPtr<FontFace> > matchedFonts; |
| 295 | 345 |
| 296 Font font; | 346 Font font; |
| 297 if (!resolveFontStyle(fontString, font)) { | 347 if (!resolveFontStyle(fontString, font)) { |
| 298 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 348 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
| 299 return matchedFonts; | 349 return matchedFonts; |
| 300 } | 350 } |
| 301 | 351 |
| 352 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
| 302 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 353 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
| 303 CSSSegmentedFontFace* face = document()->styleEngine()->fontSelector()->
getFontFace(font.fontDescription(), f->family()); | 354 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
| 304 if (face) | 355 if (face) |
| 305 matchedFonts.append(face->fontFaces(nullToSpace(text))); | 356 matchedFonts.append(face->fontFaces(nullToSpace(text))); |
| 306 } | 357 } |
| 307 return matchedFonts; | 358 return matchedFonts; |
| 308 } | 359 } |
| 309 | 360 |
| 310 ScriptPromise FontFaceSet::load(const String& fontString, const String& text, Ex
ceptionState& exceptionState) | 361 ScriptPromise FontFaceSet::load(const String& fontString, const String& text, Ex
ceptionState& exceptionState) |
| 311 { | 362 { |
| 312 Font font; | 363 Font font; |
| 313 if (!resolveFontStyle(fontString, font)) { | 364 if (!resolveFontStyle(fontString, font)) { |
| 314 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 365 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
| 315 return ScriptPromise(); | 366 return ScriptPromise(); |
| 316 } | 367 } |
| 317 | 368 |
| 318 Document* d = document(); | 369 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
| 319 ScriptPromise promise = ScriptPromise::createPending(executionContext()); | 370 ScriptPromise promise = ScriptPromise::createPending(executionContext()); |
| 320 RefPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(f
ont.family(), promise, executionContext()); | 371 RefPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(f
ont.family(), promise, executionContext()); |
| 321 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 372 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
| 322 CSSSegmentedFontFace* face = d->styleEngine()->fontSelector()->getFontFa
ce(font.fontDescription(), f->family()); | 373 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
| 323 if (!face) { | 374 if (!face) { |
| 324 resolver->error(); | 375 resolver->error(); |
| 325 continue; | 376 continue; |
| 326 } | 377 } |
| 327 face->loadFont(font.fontDescription(), nullToSpace(text), resolver); | 378 face->loadFont(font.fontDescription(), nullToSpace(text), resolver); |
| 328 } | 379 } |
| 329 return promise; | 380 return promise; |
| 330 } | 381 } |
| 331 | 382 |
| 332 bool FontFaceSet::check(const String& fontString, const String& text, ExceptionS
tate& exceptionState) | 383 bool FontFaceSet::check(const String& fontString, const String& text, ExceptionS
tate& exceptionState) |
| 333 { | 384 { |
| 334 Font font; | 385 Font font; |
| 335 if (!resolveFontStyle(fontString, font)) { | 386 if (!resolveFontStyle(fontString, font)) { |
| 336 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); | 387 exceptionState.throwDOMException(SyntaxError, "Could not resolve '" + fo
ntString + "' as a font."); |
| 337 return false; | 388 return false; |
| 338 } | 389 } |
| 339 | 390 |
| 391 CSSSegmentedFontFaceCache* cssSegmentedFontFaceCache = document()->styleEngi
ne()->fontSelector()->cssSegmentedFontFaceCache(); |
| 340 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 392 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
| 341 CSSSegmentedFontFace* face = document()->styleEngine()->fontSelector()->
getFontFace(font.fontDescription(), f->family()); | 393 CSSSegmentedFontFace* face = cssSegmentedFontFaceCache->get(font.fontDes
cription(), f->family()); |
| 342 if (!face || !face->checkFont(nullToSpace(text))) | 394 if (!face || !face->checkFont(nullToSpace(text))) |
| 343 return false; | 395 return false; |
| 344 } | 396 } |
| 345 return true; | 397 return true; |
| 346 } | 398 } |
| 347 | 399 |
| 348 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) | 400 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) |
| 349 { | 401 { |
| 350 if (fontString.isEmpty()) | 402 if (fontString.isEmpty()) |
| 351 return false; | 403 return false; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 } | 468 } |
| 417 | 469 |
| 418 void FontFaceSet::didLayout(Document* document) | 470 void FontFaceSet::didLayout(Document* document) |
| 419 { | 471 { |
| 420 if (FontFaceSet* fonts = static_cast<FontFaceSet*>(SupplementType::from(docu
ment, supplementName()))) | 472 if (FontFaceSet* fonts = static_cast<FontFaceSet*>(SupplementType::from(docu
ment, supplementName()))) |
| 421 fonts->didLayout(); | 473 fonts->didLayout(); |
| 422 } | 474 } |
| 423 | 475 |
| 424 | 476 |
| 425 } // namespace WebCore | 477 } // namespace WebCore |
| OLD | NEW |