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 |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND | 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 | 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 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 | 16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE |
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 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 | 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
23 * DAMAGE. | 23 * DAMAGE. |
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 "V8FontFaceSet.h" | |
30 #include "bindings/v8/Dictionary.h" | 31 #include "bindings/v8/Dictionary.h" |
32 #include "bindings/v8/ScriptPromiseResolver.h" | |
33 #include "bindings/v8/ScriptScope.h" | |
34 #include "bindings/v8/ScriptState.h" | |
31 #include "core/css/CSSFontFaceLoadEvent.h" | 35 #include "core/css/CSSFontFaceLoadEvent.h" |
32 #include "core/css/CSSFontFaceSource.h" | 36 #include "core/css/CSSFontFaceSource.h" |
33 #include "core/css/CSSFontSelector.h" | 37 #include "core/css/CSSFontSelector.h" |
34 #include "core/css/CSSParser.h" | 38 #include "core/css/CSSParser.h" |
35 #include "core/css/CSSSegmentedFontFace.h" | 39 #include "core/css/CSSSegmentedFontFace.h" |
36 #include "core/css/StylePropertySet.h" | 40 #include "core/css/StylePropertySet.h" |
37 #include "core/css/resolver/StyleResolver.h" | 41 #include "core/css/resolver/StyleResolver.h" |
38 #include "core/dom/Document.h" | 42 #include "core/dom/Document.h" |
39 #include "core/page/FrameView.h" | 43 #include "core/page/FrameView.h" |
40 #include "core/platform/HistogramSupport.h" | 44 #include "core/platform/HistogramSupport.h" |
41 | 45 |
42 namespace WebCore { | 46 namespace WebCore { |
43 | 47 |
44 static const int defaultFontSize = 10; | 48 static const int defaultFontSize = 10; |
45 static const char* const defaultFontFamily = "sans-serif"; | 49 static const char* const defaultFontFamily = "sans-serif"; |
46 | 50 |
47 class LoadFontCallback : public CSSSegmentedFontFace::LoadFontCallback { | 51 class LoadFontPromiseResolver : public CSSSegmentedFontFace::LoadFontCallback { |
48 public: | 52 public: |
49 static PassRefPtr<LoadFontCallback> create(int numLoading, PassRefPtr<VoidCa llback> loadCallback, PassRefPtr<VoidCallback> errorCallback) | 53 static PassRefPtr<LoadFontPromiseResolver> create(const FontFamily& family, ScriptExecutionContext* context) |
50 { | 54 { |
51 return adoptRef<LoadFontCallback>(new LoadFontCallback(numLoading, loadC allback, errorCallback)); | |
52 } | |
53 | |
54 static PassRefPtr<LoadFontCallback> createFromParams(const Dictionary& param s, const FontFamily& family) | |
55 { | |
56 RefPtr<VoidCallback> onsuccess; | |
57 RefPtr<VoidCallback> onerror; | |
58 params.get("onsuccess", onsuccess); | |
59 params.get("onerror", onerror); | |
60 if (!onsuccess && !onerror) | |
61 return 0; | |
62 int numFamilies = 0; | 55 int numFamilies = 0; |
63 for (const FontFamily* f = &family; f; f = f->next()) | 56 for (const FontFamily* f = &family; f; f = f->next()) |
64 numFamilies++; | 57 numFamilies++; |
65 return LoadFontCallback::create(numFamilies, onsuccess, onerror); | 58 return adoptRef<LoadFontPromiseResolver>(new LoadFontPromiseResolver(num Families, context)); |
66 } | 59 } |
67 | 60 |
68 virtual void notifyLoaded(CSSSegmentedFontFace*) OVERRIDE; | 61 virtual void notifyLoaded(CSSSegmentedFontFace*) OVERRIDE; |
69 virtual void notifyError(CSSSegmentedFontFace*) OVERRIDE; | 62 virtual void notifyError(CSSSegmentedFontFace*) OVERRIDE; |
70 void loaded(Document*); | 63 void loaded(Document*); |
71 void error(Document*); | 64 void error(Document*); |
65 void resolve(); | |
66 | |
67 ScriptPromise promise() | |
68 { | |
69 ScriptPromise promise = m_resolver->promise(); | |
70 m_resolver->detachPromise(); | |
71 return promise; | |
72 } | |
73 | |
72 private: | 74 private: |
73 LoadFontCallback(int numLoading, PassRefPtr<VoidCallback> loadCallback, Pass RefPtr<VoidCallback> errorCallback) | 75 LoadFontPromiseResolver(int numLoading, ScriptExecutionContext* context) |
74 : m_numLoading(numLoading) | 76 : m_numLoading(numLoading) |
75 , m_errorOccured(false) | 77 , m_errorOccured(false) |
76 , m_loadCallback(loadCallback) | 78 , m_scriptState(ScriptState::current()) |
77 , m_errorCallback(errorCallback) | 79 , m_resolver(ScriptPromiseResolver::create(context)) |
78 { } | 80 { } |
79 | 81 |
80 int m_numLoading; | 82 int m_numLoading; |
81 bool m_errorOccured; | 83 bool m_errorOccured; |
82 RefPtr<VoidCallback> m_loadCallback; | 84 ScriptState* m_scriptState; |
83 RefPtr<VoidCallback> m_errorCallback; | 85 RefPtr<ScriptPromiseResolver> m_resolver; |
84 }; | 86 }; |
85 | 87 |
86 void LoadFontCallback::loaded(Document* document) | 88 void LoadFontPromiseResolver::loaded(Document* document) |
87 { | 89 { |
88 m_numLoading--; | 90 m_numLoading--; |
89 if (m_numLoading || !document) | 91 if (m_numLoading || !document) |
90 return; | 92 return; |
91 | 93 |
92 if (m_errorOccured) { | 94 document->fonts()->scheduleResolve(this); |
93 if (m_errorCallback) | |
94 document->fonts()->scheduleCallback(m_errorCallback.release()); | |
95 } else { | |
96 if (m_loadCallback) | |
97 document->fonts()->scheduleCallback(m_loadCallback.release()); | |
98 } | |
99 } | 95 } |
100 | 96 |
101 void LoadFontCallback::error(Document* document) | 97 void LoadFontPromiseResolver::error(Document* document) |
102 { | 98 { |
103 m_errorOccured = true; | 99 m_errorOccured = true; |
104 loaded(document); | 100 loaded(document); |
105 } | 101 } |
106 | 102 |
107 void LoadFontCallback::notifyLoaded(CSSSegmentedFontFace* face) | 103 void LoadFontPromiseResolver::notifyLoaded(CSSSegmentedFontFace* face) |
108 { | 104 { |
109 loaded(face->fontSelector()->document()); | 105 loaded(face->fontSelector()->document()); |
110 } | 106 } |
111 | 107 |
112 void LoadFontCallback::notifyError(CSSSegmentedFontFace* face) | 108 void LoadFontPromiseResolver::notifyError(CSSSegmentedFontFace* face) |
113 { | 109 { |
114 error(face->fontSelector()->document()); | 110 error(face->fontSelector()->document()); |
115 } | 111 } |
116 | 112 |
113 void LoadFontPromiseResolver::resolve() | |
114 { | |
115 ScriptScope scope(m_scriptState); | |
116 if (m_errorOccured) | |
117 m_resolver->reject(ScriptValue::createNull()); | |
118 else | |
119 m_resolver->fulfill(ScriptValue::createNull()); | |
120 } | |
121 | |
122 class FontsReadyPromiseResolver { | |
123 public: | |
124 static PassOwnPtr<FontsReadyPromiseResolver> create(ScriptExecutionContext* context) | |
125 { | |
126 return adoptPtr(new FontsReadyPromiseResolver(context)); | |
127 } | |
128 | |
129 void call(PassRefPtr<FontFaceSet> fontFaceSet) | |
130 { | |
131 ScriptScope scope(m_scriptState); | |
132 m_resolver->fulfill(fontFaceSet); | |
133 } | |
134 | |
135 ScriptPromise promise() | |
136 { | |
137 ScriptPromise promise = m_resolver->promise(); | |
138 m_resolver->detachPromise(); | |
139 return promise; | |
140 } | |
141 | |
142 private: | |
143 FontsReadyPromiseResolver(ScriptExecutionContext* context) | |
144 : m_scriptState(ScriptState::current()) | |
145 , m_resolver(ScriptPromiseResolver::create(context)) | |
146 { } | |
147 ScriptState* m_scriptState; | |
148 RefPtr<ScriptPromiseResolver> m_resolver; | |
149 }; | |
150 | |
117 FontFaceSet::FontFaceSet(Document* document) | 151 FontFaceSet::FontFaceSet(Document* document) |
118 : ActiveDOMObject(document) | 152 : ActiveDOMObject(document) |
119 , m_loadingCount(0) | 153 , m_loadingCount(0) |
120 , m_shouldFireDoneEvent(false) | 154 , m_shouldFireDoneEvent(false) |
121 , m_timer(this, &FontFaceSet::timerFired) | 155 , m_timer(this, &FontFaceSet::timerFired) |
122 { | 156 { |
123 suspendIfNeeded(); | 157 suspendIfNeeded(); |
124 } | 158 } |
125 | 159 |
126 FontFaceSet::~FontFaceSet() | 160 FontFaceSet::~FontFaceSet() |
(...skipping 25 matching lines...) Expand all Loading... | |
152 return ActiveDOMObject::scriptExecutionContext(); | 186 return ActiveDOMObject::scriptExecutionContext(); |
153 } | 187 } |
154 | 188 |
155 void FontFaceSet::didLayout() | 189 void FontFaceSet::didLayout() |
156 { | 190 { |
157 Document* d = document(); | 191 Document* d = document(); |
158 if (d->page() && d->page()->mainFrame() == d->frame()) | 192 if (d->page() && d->page()->mainFrame() == d->frame()) |
159 m_histogram.record(); | 193 m_histogram.record(); |
160 if (!RuntimeEnabledFeatures::fontLoadEventsEnabled()) | 194 if (!RuntimeEnabledFeatures::fontLoadEventsEnabled()) |
161 return; | 195 return; |
162 if (m_loadingCount || (!m_shouldFireDoneEvent && m_fontsReadyCallbacks.isEmp ty())) | 196 if (m_loadingCount || (!m_shouldFireDoneEvent && m_readyResolvers.isEmpty()) ) |
163 return; | 197 return; |
164 if (!m_timer.isActive()) | 198 if (!m_timer.isActive()) |
165 m_timer.startOneShot(0); | 199 m_timer.startOneShot(0); |
166 } | 200 } |
167 | 201 |
168 void FontFaceSet::timerFired(Timer<FontFaceSet>*) | 202 void FontFaceSet::timerFired(Timer<FontFaceSet>*) |
169 { | 203 { |
170 firePendingEvents(); | 204 firePendingEvents(); |
171 firePendingCallbacks(); | 205 resolvePendingLoadPromises(); |
172 fireDoneEventIfPossible(); | 206 fireDoneEventIfPossible(); |
173 } | 207 } |
174 | 208 |
175 void FontFaceSet::scheduleEvent(PassRefPtr<Event> event) | 209 void FontFaceSet::scheduleEvent(PassRefPtr<Event> event) |
176 { | 210 { |
177 m_pendingEvents.append(event); | 211 m_pendingEvents.append(event); |
178 if (!m_timer.isActive()) | 212 if (!m_timer.isActive()) |
179 m_timer.startOneShot(0); | 213 m_timer.startOneShot(0); |
180 } | 214 } |
181 | 215 |
182 void FontFaceSet::firePendingEvents() | 216 void FontFaceSet::firePendingEvents() |
183 { | 217 { |
184 if (m_pendingEvents.isEmpty()) | 218 if (m_pendingEvents.isEmpty()) |
185 return; | 219 return; |
186 | 220 |
187 Vector<RefPtr<Event> > pendingEvents; | 221 Vector<RefPtr<Event> > pendingEvents; |
188 m_pendingEvents.swap(pendingEvents); | 222 m_pendingEvents.swap(pendingEvents); |
189 for (size_t index = 0; index < pendingEvents.size(); ++index) | 223 for (size_t index = 0; index < pendingEvents.size(); ++index) |
190 dispatchEvent(pendingEvents[index].release()); | 224 dispatchEvent(pendingEvents[index].release()); |
191 } | 225 } |
192 | 226 |
193 void FontFaceSet::scheduleCallback(PassRefPtr<VoidCallback> callback) | 227 void FontFaceSet::scheduleResolve(LoadFontPromiseResolver* resolver) |
194 { | 228 { |
195 m_pendingCallbacks.append(callback); | 229 m_pendingLoadResolvers.append(resolver); |
196 if (!m_timer.isActive()) | 230 if (!m_timer.isActive()) |
197 m_timer.startOneShot(0); | 231 m_timer.startOneShot(0); |
198 } | 232 } |
199 | 233 |
200 void FontFaceSet::firePendingCallbacks() | 234 void FontFaceSet::resolvePendingLoadPromises() |
201 { | 235 { |
202 if (m_pendingCallbacks.isEmpty()) | 236 if (m_pendingLoadResolvers.isEmpty()) |
203 return; | 237 return; |
204 | 238 |
205 Vector<RefPtr<VoidCallback> > pendingCallbacks; | 239 Vector<RefPtr<LoadFontPromiseResolver> > resolvers; |
206 m_pendingCallbacks.swap(pendingCallbacks); | 240 m_pendingLoadResolvers.swap(resolvers); |
207 for (size_t index = 0; index < pendingCallbacks.size(); ++index) | 241 for (size_t index = 0; index < resolvers.size(); ++index) |
208 pendingCallbacks[index]->handleEvent(); | 242 resolvers[index]->resolve(); |
209 } | 243 } |
210 | 244 |
211 void FontFaceSet::beginFontLoading(FontFace* fontFace) | 245 void FontFaceSet::beginFontLoading(FontFace* fontFace) |
212 { | 246 { |
213 m_histogram.incrementCount(); | 247 m_histogram.incrementCount(); |
214 if (!RuntimeEnabledFeatures::fontLoadEventsEnabled()) | 248 if (!RuntimeEnabledFeatures::fontLoadEventsEnabled()) |
215 return; | 249 return; |
216 | 250 |
217 ++m_loadingCount; | 251 ++m_loadingCount; |
218 if (m_loadingCount == 1 && !m_shouldFireDoneEvent) | 252 if (m_loadingCount == 1 && !m_shouldFireDoneEvent) |
(...skipping 22 matching lines...) Expand all Loading... | |
241 ASSERT(m_loadingCount > 0); | 275 ASSERT(m_loadingCount > 0); |
242 --m_loadingCount; | 276 --m_loadingCount; |
243 if (!m_loadingCount) { | 277 if (!m_loadingCount) { |
244 ASSERT(!m_shouldFireDoneEvent); | 278 ASSERT(!m_shouldFireDoneEvent); |
245 m_shouldFireDoneEvent = true; | 279 m_shouldFireDoneEvent = true; |
246 if (!m_timer.isActive()) | 280 if (!m_timer.isActive()) |
247 m_timer.startOneShot(0); | 281 m_timer.startOneShot(0); |
248 } | 282 } |
249 } | 283 } |
250 | 284 |
251 void FontFaceSet::notifyWhenFontsReady(PassRefPtr<VoidCallback> callback) | 285 ScriptPromise FontFaceSet::ready() |
252 { | 286 { |
253 m_fontsReadyCallbacks.append(callback); | 287 OwnPtr<FontsReadyPromiseResolver> resolver = FontsReadyPromiseResolver::crea te(scriptExecutionContext()); |
288 ScriptPromise promise = resolver->promise(); | |
289 m_readyResolvers.append(resolver.release()); | |
254 if (!m_timer.isActive()) | 290 if (!m_timer.isActive()) |
255 m_timer.startOneShot(0); | 291 m_timer.startOneShot(0); |
292 return promise; | |
256 } | 293 } |
257 | 294 |
258 void FontFaceSet::fireDoneEventIfPossible() | 295 void FontFaceSet::fireDoneEventIfPossible() |
259 { | 296 { |
260 if (!m_pendingEvents.isEmpty() || !m_pendingCallbacks.isEmpty()) | 297 if (!m_pendingEvents.isEmpty() || !m_pendingLoadResolvers.isEmpty()) |
261 return; | 298 return; |
262 if (m_loadingCount || (!m_shouldFireDoneEvent && m_fontsReadyCallbacks.isEmp ty())) | 299 if (m_loadingCount || (!m_shouldFireDoneEvent && m_readyResolvers.isEmpty()) ) |
263 return; | 300 return; |
264 | 301 |
265 // If the layout was invalidated in between when we thought layout | 302 // If the layout was invalidated in between when we thought layout |
266 // was updated and when we're ready to fire the event, just wait | 303 // was updated and when we're ready to fire the event, just wait |
267 // until after the next layout before firing events. | 304 // until after the next layout before firing events. |
268 Document* d = document(); | 305 Document* d = document(); |
269 if (!d->view() || d->view()->needsLayout()) | 306 if (!d->view() || d->view()->needsLayout()) |
270 return; | 307 return; |
271 | 308 |
272 if (m_shouldFireDoneEvent) { | 309 if (m_shouldFireDoneEvent) { |
273 m_shouldFireDoneEvent = false; | 310 m_shouldFireDoneEvent = false; |
274 RefPtr<CSSFontFaceLoadEvent> doneEvent; | 311 RefPtr<CSSFontFaceLoadEvent> doneEvent; |
275 RefPtr<CSSFontFaceLoadEvent> errorEvent; | 312 RefPtr<CSSFontFaceLoadEvent> errorEvent; |
276 doneEvent = CSSFontFaceLoadEvent::createForFontFaces(eventNames().loadin gdoneEvent, m_loadedFonts); | 313 doneEvent = CSSFontFaceLoadEvent::createForFontFaces(eventNames().loadin gdoneEvent, m_loadedFonts); |
277 m_loadedFonts.clear(); | 314 m_loadedFonts.clear(); |
278 if (!m_failedFonts.isEmpty()) { | 315 if (!m_failedFonts.isEmpty()) { |
279 errorEvent = CSSFontFaceLoadEvent::createForFontFaces(eventNames().l oadingerrorEvent, m_failedFonts); | 316 errorEvent = CSSFontFaceLoadEvent::createForFontFaces(eventNames().l oadingerrorEvent, m_failedFonts); |
280 m_failedFonts.clear(); | 317 m_failedFonts.clear(); |
281 } | 318 } |
282 dispatchEvent(doneEvent); | 319 dispatchEvent(doneEvent); |
283 if (errorEvent) | 320 if (errorEvent) |
284 dispatchEvent(errorEvent); | 321 dispatchEvent(errorEvent); |
285 } | 322 } |
286 | 323 |
287 if (!m_fontsReadyCallbacks.isEmpty()) { | 324 if (!m_readyResolvers.isEmpty()) { |
288 Vector<RefPtr<VoidCallback> > callbacks; | 325 Vector<OwnPtr<FontsReadyPromiseResolver> > resolvers; |
289 m_fontsReadyCallbacks.swap(callbacks); | 326 m_readyResolvers.swap(resolvers); |
290 for (size_t index = 0; index < callbacks.size(); ++index) | 327 for (size_t index = 0; index < resolvers.size(); ++index) |
291 callbacks[index]->handleEvent(); | 328 resolvers[index]->call(this); |
292 } | 329 } |
293 } | 330 } |
294 | 331 |
295 void FontFaceSet::loadFont(const Dictionary& params) | 332 Vector<RefPtr<FontFace> > FontFaceSet::match(const String& fontString, const Str ing&, ExceptionState& es) |
296 { | 333 { |
297 // FIXME: The text member of params is ignored. | 334 // FIXME: The second parameter (text) is ignored. |
298 String fontString; | 335 Vector<RefPtr<FontFace> > matchedFonts; |
299 if (!params.get("font", fontString)) | 336 |
300 return; | |
301 Font font; | 337 Font font; |
302 if (!resolveFontStyle(fontString, font)) | 338 if (!resolveFontStyle(fontString, font)) { |
303 return; | 339 es.throwDOMException(SyntaxError); |
304 RefPtr<LoadFontCallback> callback = LoadFontCallback::createFromParams(param s, font.family()); | 340 return matchedFonts; |
341 } | |
305 | 342 |
306 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 343 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
307 Document* d = document(); | 344 CSSSegmentedFontFace* face = document()->styleResolver()->fontSelector() ->getFontFace(font.fontDescription(), f->family()); |
308 CSSSegmentedFontFace* face = d->styleResolver()->fontSelector()->getFont Face(font.fontDescription(), f->family()); | 345 if (face) |
309 if (!face) { | 346 matchedFonts.append(face->fontFaces()); |
310 if (callback) | |
311 callback->error(d); | |
312 continue; | |
313 } | |
314 face->loadFont(font.fontDescription(), callback); | |
315 } | 347 } |
348 return matchedFonts; | |
316 } | 349 } |
317 | 350 |
318 bool FontFaceSet::checkFont(const String& fontString, const String&) | 351 ScriptPromise FontFaceSet::load(const String& fontString, const String&, Excepti onState& es) |
319 { | 352 { |
320 // FIXME: The second parameter (text) is ignored. | 353 // FIXME: The second parameter (text) is ignored. |
321 Font font; | 354 Font font; |
322 if (!resolveFontStyle(fontString, font)) | 355 if (!resolveFontStyle(fontString, font)) { |
356 es.throwDOMException(SyntaxError); | |
357 return ScriptPromise(); | |
358 } | |
359 | |
360 Document* d = document(); | |
361 RefPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(f ont.family(), scriptExecutionContext()); | |
362 for (const FontFamily* f = &font.family(); f; f = f->next()) { | |
363 CSSSegmentedFontFace* face = d->styleResolver()->fontSelector()->getFont Face(font.fontDescription(), f->family()); | |
364 if (!face) { | |
365 resolver->error(d); | |
366 continue; | |
367 } | |
368 face->loadFont(font.fontDescription(), resolver); | |
369 } | |
370 return resolver->promise(); | |
371 } | |
372 | |
373 bool FontFaceSet::check(const String& fontString, const String&, ExceptionState& es) | |
374 { | |
375 // FIXME: The second parameter (text) is ignored. | |
376 Font font; | |
377 if (!resolveFontStyle(fontString, font)) { | |
378 es.throwDOMException(SyntaxError); | |
323 return false; | 379 return false; |
380 } | |
381 | |
324 for (const FontFamily* f = &font.family(); f; f = f->next()) { | 382 for (const FontFamily* f = &font.family(); f; f = f->next()) { |
325 CSSSegmentedFontFace* face = document()->styleResolver()->fontSelector() ->getFontFace(font.fontDescription(), f->family()); | 383 CSSSegmentedFontFace* face = document()->styleResolver()->fontSelector() ->getFontFace(font.fontDescription(), f->family()); |
326 if (!face || !face->checkFont()) | 384 if (!face || !face->checkFont()) |
327 return false; | 385 return false; |
328 } | 386 } |
329 return true; | 387 return true; |
330 } | 388 } |
331 | 389 |
332 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) | 390 bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) |
333 { | 391 { |
392 if (fontString.isEmpty()) | |
eseidel
2013/09/19 04:11:18
I believe (!fontString) is equivalent, but this is
Kunihiko Sakamoto
2013/09/19 04:49:31
!s is equivalent to !s.isNull(), but we don't want
| |
393 return false; | |
394 | |
334 // Interpret fontString in the same way as the 'font' attribute of CanvasRen deringContext2D. | 395 // Interpret fontString in the same way as the 'font' attribute of CanvasRen deringContext2D. |
335 RefPtr<MutableStylePropertySet> parsedStyle = MutableStylePropertySet::creat e(); | 396 RefPtr<MutableStylePropertySet> parsedStyle = MutableStylePropertySet::creat e(); |
336 CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0); | 397 CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0); |
337 if (parsedStyle->isEmpty()) | 398 if (parsedStyle->isEmpty()) |
338 return false; | 399 return false; |
339 | 400 |
340 String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); | 401 String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); |
341 if (fontValue == "inherit" || fontValue == "initial") | 402 if (fontValue == "inherit" || fontValue == "initial") |
342 return false; | 403 return false; |
343 | 404 |
(...skipping 30 matching lines...) Expand all Loading... | |
374 | 435 |
375 void FontFaceSet::FontLoadHistogram::record() | 436 void FontFaceSet::FontLoadHistogram::record() |
376 { | 437 { |
377 if (m_recorded) | 438 if (m_recorded) |
378 return; | 439 return; |
379 m_recorded = true; | 440 m_recorded = true; |
380 HistogramSupport::histogramCustomCounts("WebFont.WebFontsInPage", m_count, 1 , 100, 50); | 441 HistogramSupport::histogramCustomCounts("WebFont.WebFontsInPage", m_count, 1 , 100, 50); |
381 } | 442 } |
382 | 443 |
383 } // namespace WebCore | 444 } // namespace WebCore |
OLD | NEW |