KHtml

css_webfont.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2009 Germain Garand <[email protected]>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "css_webfont.h"
28 #include "css/css_ruleimpl.h"
29 #include "css/cssproperties.h"
30 #include "css/cssvalues.h"
31 #include "xml/dom_docimpl.h"
32 #include "rendering/font.h"
33 #include "rendering/render_object.h"
34 #include "rendering/render_canvas.h"
35 #include "khtml_debug.h"
36 #include <QFontDatabase>
37 #include <QFont>
38 
39 namespace DOM
40 {
41 
42 CSSFontFaceSource::CSSFontFaceSource(const DOMString &str, bool distant)
43  : m_string(str)
44  , m_font(nullptr)
45  , m_face(nullptr)
46  , m_refed(false)
47  , m_distant(distant)
48 #if 0
49  //ENABLE(SVG_FONTS)
50  , m_svgFontFaceElement(0)
51 #endif
52 {
53  m_id = -1;
54 }
55 
56 CSSFontFaceSource::~CSSFontFaceSource()
57 {
58  if (m_font) {
59  if (m_refed) {
60  m_font->deref(this);
61  }
62  if (m_id != -1) {
63  WTF::Vector<DOMString> names = m_face->familyNames();
64  unsigned size = names.size();
65  for (unsigned i = 0; i < size; i++) {
66  QFont::removeSubstitutions(names[i].string());
67  khtml::Font::invalidateCachedFontFamily(names[i].string());
68  }
70  }
71  }
72 }
73 
74 bool CSSFontFaceSource::isLoaded() const
75 {
76  if (m_distant) {
77  return m_font ? m_font->isLoaded() : false;
78  }
79  return true;
80 }
81 
82 bool CSSFontFaceSource::isValid() const
83 {
84  if (m_font) {
85  return !m_font->hadError();
86  }
87  return true;
88 }
89 
90 void CSSFontFaceSource::notifyFinished(khtml::CachedObject *finishedObj)
91 {
92  // Nothing to do if font already added from other src or failed to download
93  if (m_face->installed() || finishedObj->hadError()) {
94  return;
95  }
96 
97  WTF::Vector<DOMString> names = m_face->familyNames();
98  const unsigned size = names.size();
99 
100  m_id = QFontDatabase::addApplicationFontFromData(m_font->font());
101 
102  if (m_id == -1) {
103  // qCDebug(KHTML_LOG) << "WARNING: downloaded web font" << (size?names[0].string():QString()) << "was rejected by the font subsystem.";
104  return;
105  }
106 
107  m_face->setInstalled();
108 
109  QString nativeName = QFontDatabase::applicationFontFamilies(m_id)[0];
110  for (unsigned i = 0; i < size; i++) {
111  if (names[i].string() != nativeName) {
112  QFont::insertSubstitution(names[i].string(), nativeName);
113  }
114  khtml::Font::invalidateCachedFontFamily(names[i].string());
115  }
116 
117  if (m_face && m_refed) {
118  m_face->fontLoaded(this);
119  }
120 }
121 
122 void CSSFontFaceSource::refLoader()
123 {
124  if (!m_distant) {
125  return;
126  }
127  if (!m_font) {
128  assert(m_face);
129  m_font = m_face->fontSelector()->docLoader()->requestFont(m_string);
130  }
131  if (m_font) {
132  m_font->ref(this);
133  m_refed = true;
134  }
135 }
136 
137 #if 0
138 SimpleFontData *CSSFontFaceSource::getFontData(const FontDef &fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector *fontSelector)
139 {
140  // If the font hasn't loaded or an error occurred, then we've got nothing.
141  if (!isValid()) {
142  return 0;
143  }
144 
145 #if 0
146  // ENABLE(SVG_FONTS)
147  if (!m_font && !m_svgFontFaceElement) {
148 #else
149  if (!m_font) {
150 #endif
151  FontPlatformData *data = fontCache()->getCachedFontPlatformData(fontDescription, m_string);
152  SimpleFontData *fontData = fontCache()->getCachedFontData(data);
153 
154  // We're local. Just return a SimpleFontData from the normal cache.
155  return fontData;
156  }
157 
158  // See if we have a mapping in our FontData cache.
159  unsigned hashKey = fontDescription.computedPixelSize() << 2 | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0);
160  if (SimpleFontData *cachedData = m_fontDataTable.get(hashKey)) {
161  return cachedData;
162  }
163 
164  OwnPtr<SimpleFontData> fontData;
165 
166  // If we are still loading, then we let the system pick a font.
167  if (isLoaded()) {
168  if (m_font) {
169 #if 0
170  //ENABLE(SVG_FONTS)
171  if (m_font->isSVGFont()) {
172  // For SVG fonts parse the external SVG document, and extract the <font> element.
173  if (!m_font->ensureSVGFontData()) {
174  return 0;
175  }
176 
177  if (!m_externalSVGFontElement) {
178  m_externalSVGFontElement = m_font->getSVGFontById(SVGURIReference::getTarget(m_string));
179  }
180 
181  if (!m_externalSVGFontElement) {
182  return 0;
183  }
184 
185  SVGFontFaceElement *fontFaceElement = 0;
186 
187  // Select first <font-face> child
188  for (Node *fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) {
189  if (fontChild->hasTagName(SVGNames::font_faceTag)) {
190  fontFaceElement = static_cast<SVGFontFaceElement *>(fontChild);
191  break;
192  }
193  }
194 
195  if (fontFaceElement) {
196  if (!m_svgFontFaceElement) {
197  // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement.
198  // Use the imported <font-face> tag as referencing font-face element for these cases.
199  m_svgFontFaceElement = fontFaceElement;
200  }
201 
202  SVGFontData *svgFontData = new SVGFontData(fontFaceElement);
203  fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.renderingMode()), true, false, svgFontData));
204  }
205  } else
206 #endif
207  {
208  // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef.
209  if (!m_font->ensureCustomFontData()) {
210  return 0;
211  }
212 
213  fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.renderingMode()), true, false));
214  }
215  } else {
216 #if 0
217  //ENABLE(SVG_FONTS)
218  // In-Document SVG Fonts
219  if (m_svgFontFaceElement) {
220  SVGFontData *svgFontData = new SVGFontData(m_svgFontFaceElement);
221  fontData.set(new SimpleFontData(FontPlatformData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic), true, false, svgFontData));
222  }
223 #endif
224  }
225  } else {
226  // Kick off the load now.
227  if (DocLoader *docLoader = fontSelector->docLoader()) {
228  m_font->beginLoadIfNeeded(docLoader);
229  }
230  // FIXME: m_string is a URL so it makes no sense to pass it as a family name.
231  FontPlatformData *tempData = fontCache()->getCachedFontPlatformData(fontDescription, m_string);
232  if (!tempData) {
233  tempData = fontCache()->getLastResortFallbackFont(fontDescription);
234  }
235  fontData.set(new SimpleFontData(*tempData, true, true));
236  }
237 
238  m_fontDataTable.set(hashKey, fontData.get());
239  return fontData.release();
240 }
241 #endif
242 
243 CSSFontFace::~CSSFontFace()
244 {
245  deleteAllValues(m_sources);
246 }
247 
248 bool CSSFontFace::isLoaded() const
249 {
250  unsigned size = m_sources.size();
251  for (unsigned i = 0; i < size; i++) {
252  if (!m_sources[i]->isLoaded()) {
253  return false;
254  }
255  }
256  return true;
257 }
258 
259 bool CSSFontFace::isValid() const
260 {
261  unsigned size = m_sources.size();
262  if (!size) {
263  return false;
264  }
265  for (unsigned i = 0; i < size; i++) {
266  if (m_sources[i]->isValid()) {
267  return true;
268  }
269  }
270  return false;
271 }
272 
273 void CSSFontFace::setInstalled()
274 {
275  m_installed = true;
276 }
277 
278 bool CSSFontFace::installed() const
279 {
280  return m_installed;
281 }
282 
283 void CSSFontFace::refLoaders()
284 {
285  if (m_refed) {
286  return;
287  }
288  unsigned size = m_sources.size();
289  if (!size) {
290  return;
291  }
292  for (unsigned i = 0; i < size; i++) {
293  m_sources[i]->refLoader();
294  }
295  m_refed = true;
296 }
297 
298 void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace *segmentedFontFace)
299 {
300  (void) segmentedFontFace;
301 // m_segmentedFontFaces.add(segmentedFontFace);
302 }
303 
304 void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace *segmentedFontFace)
305 {
306  (void) segmentedFontFace;
307 // m_segmentedFontFaces.remove(segmentedFontFace);
308 }
309 
310 void CSSFontFace::addSource(CSSFontFaceSource *source)
311 {
312  m_sources.append(source);
313  source->setFontFace(this);
314 }
315 
316 void CSSFontFace::fontLoaded(CSSFontFaceSource *)
317 {
318  /*
319  // FIXME: Can we assert that m_segmentedFontFaces is not empty? That may
320  // require stopping in-progress font loading when the last
321  // CSSSegmentedFontFace is removed.
322  if (m_segmentedFontFaces.isEmpty())
323  return;
324 
325  HashSet<CSSSegmentedFontFace*>::iterator end = m_segmentedFontFaces.end();
326  for (HashSet<CSSSegmentedFontFace*>::iterator it = m_segmentedFontFaces.begin(); it != end; ++it)
327  (*it)->fontLoaded(this);
328 
329  // Use one of the CSSSegmentedFontFaces' font selector. They all have
330  // the same font selector, so it's wasteful to store it in the CSSFontFace.
331  CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
332  */
333  m_fontSelector->fontLoaded();
334 }
335 
336 #if 0
337 SimpleFontData *CSSFontFace::getFontData(const FontDef &fontDescription, bool syntheticBold, bool syntheticItalic)
338 {
339  if (!isValid()) {
340  return 0;
341  }
342 
343  ASSERT(!m_segmentedFontFaces.isEmpty());
344  CSSFontSelector *fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
345 
346  SimpleFontData *result = 0;
347  unsigned size = m_sources.size();
348  for (unsigned i = 0; i < size && !result; i++) {
349  result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector);
350  }
351  return result;
352 }
353 #endif
354 
355 CSSFontSelector::CSSFontSelector(DocumentImpl *document)
356  : m_document(document)
357 {
358  assert(m_document);
359 // fontCache()->addClient(this);
360 }
361 
362 CSSFontSelector::~CSSFontSelector()
363 {
364 // fontCache()->removeClient(this);
365 // deleteAllValues(m_fontFaces);
366 // deleteAllValues(m_locallyInstalledFontFaces);
367 // deleteAllValues(m_fonts);
368  QHash<DOMString, CSSFontFace *>::const_iterator cur = m_locallyInstalledFontFaces.constBegin();
369  QHash<DOMString, CSSFontFace *>::const_iterator end = m_locallyInstalledFontFaces.constEnd();
370  for (; cur != end; cur++) {
371  cur.value()->deref();
372  }
373 }
374 
375 bool CSSFontSelector::isEmpty() const
376 {
377  return false;
378  //return m_fonts.isEmpty();
379 }
380 
381 khtml::DocLoader *CSSFontSelector::docLoader() const
382 {
383  return m_document ? m_document->docLoader() : nullptr;
384 }
385 
386 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRuleImpl *fontFaceRule)
387 {
388  // Obtain the font-family property and the src property. Both must be defined.
389  const CSSStyleDeclarationImpl *style = fontFaceRule->style();
390  CSSValueImpl *fontFamily = style->getPropertyCSSValue(CSS_PROP_FONT_FAMILY);
391  CSSValueImpl *src = style->getPropertyCSSValue(CSS_PROP_SRC);
392  CSSValueImpl *unicodeRange = style->getPropertyCSSValue(CSS_PROP_UNICODE_RANGE);
393 
394  if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList())) {
395  return;
396  }
397 
398  CSSValueListImpl *familyList = static_cast<CSSValueListImpl *>(fontFamily);
399  if (!familyList->length()) {
400  return;
401  }
402 
403  CSSValueListImpl *srcList = static_cast<CSSValueListImpl *>(src);
404  if (!srcList->length()) {
405  return;
406  }
407 
408 // CSSValueListImpl* rangeList = static_cast<CSSValueListImpl*>(unicodeRange);
409 
410  unsigned traitsMask = 0;
411  /*
412  if (CSSValueImpl* fontStyle = style->getPropertyCSSValue(CSS_PROP_FONT_STYLE)) {
413 
414  if (fontStyle->isPrimitiveValue()) {
415  CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
416  list->append(fontStyle);
417  fontStyle = list;
418  } else if (!fontStyle->isValueList())
419  return;
420 
421  CSSValueListImpl* styleList = static_cast<CSSValueListImpl*>(fontStyle);
422  unsigned numStyles = styleList->length();
423  if (!numStyles)
424  return;
425 
426  for (unsigned i = 0; i < numStyles; ++i) {
427  switch (static_cast<CSSPrimitiveValueImpl*>(styleList[i])->getIdent()) {
428  case CSS_ALL:
429  traitsMask |= FontStyleMask;
430  break;
431  case CSS_NORMAL:
432  traitsMask |= FontStyleNormalMask;
433  break;
434  case CSS_ITALIC:
435  case CSS_OBLIQUE:
436  traitsMask |= FontStyleItalicMask;
437  break;
438  default:
439  break;
440  }
441  }
442  } else
443  traitsMask |= FontStyleMask;
444 
445  if (CSSValueImpl* fontWeight = style->getPropertyCSSValue(CSS_PROP_FONT_WEIGHT)) {
446  if (fontWeight->isPrimitiveValue()) {
447  CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
448  list->append(fontWeight);
449  fontWeight = list;
450  } else if (!fontWeight->isValueList())
451  return;
452 
453  CSSValueListImpl* weightList = static_cast<CSSValueListImpl*>(fontWeight);
454  unsigned numWeights = weightList->length();
455  if (!numWeights)
456  return;
457 
458  for (unsigned i = 0; i < numWeights; ++i) {
459  switch (static_cast<CSSPrimitiveValueImpl*>(weightList[i])->getIdent()) {
460  case CSS_VAL_ALL:
461  traitsMask |= FontWeightMask;
462  break;
463  case CSS_VAL_BOLDER:
464  case CSS_VAL_BOLD:
465  case CSS_VAL_700:
466  traitsMask |= FontWeight700Mask;
467  break;
468  case CSS_VAL_NORMAL:
469  case CSS_VAL_400:
470  traitsMask |= FontWeight400Mask;
471  break;
472  case CSS_VAL_900:
473  traitsMask |= FontWeight900Mask;
474  break;
475  case CSS_VAL_800:
476  traitsMask |= FontWeight800Mask;
477  break;
478  case CSS_VAL_600:
479  traitsMask |= FontWeight600Mask;
480  break;
481  case CSS_VAL_500:
482  traitsMask |= FontWeight500Mask;
483  break;
484  case CSS_VAL_300:
485  traitsMask |= FontWeight300Mask;
486  break;
487  case CSS_VAL_LIGHTER:
488  case CSS_VAL_200:
489  traitsMask |= FontWeight200Mask;
490  break;
491  case CSS_VAL_100:
492  traitsMask |= FontWeight100Mask;
493  break;
494  default:
495  break;
496  }
497  }
498  } else
499  traitsMask |= FontWeightMask;
500 
501  if (CSSValueImpl* fontVariant = style->getPropertyCSSValue(CSS_PROP_FONT_VARIANT)) {
502  if (fontVariant->isPrimitiveValue()) {
503  CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
504  list->append(fontVariant);
505  fontVariant = list;
506  } else if (!fontVariant->isValueList())
507  return;
508 
509  CSSValueListImpl* variantList = static_cast<CSSValueListImpl*>(fontVariant);
510  unsigned numVariants = variantList->length();
511  if (!numVariants)
512  return;
513 
514  for (unsigned i = 0; i < numVariants; ++i) {
515  switch (static_cast<CSSPrimitiveValueImpl*>(variantList[i])->getIdent()) {
516  case CSS_VAL_ALL:
517  traitsMask |= FontVariantMask;
518  break;
519  case CSS_VAL_NORMAL:
520  traitsMask |= FontVariantNormalMask;
521  break;
522  case CSS_VAL_SMALL_CAPS:
523  traitsMask |= FontVariantSmallCapsMask;
524  break;
525  default:
526  break;
527  }
528  }
529  } else
530  traitsMask |= FontVariantNormalMask;
531  */
532 
533  // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
534  CSSFontFace *fontFace = nullptr;
535 
536  const int srcLength = srcList->length();
537 
538 #if 0
539  // ENABLE(SVG_FONTS)
540  bool foundSVGFont = false;
541 #endif
542  for (int i = 0; i < srcLength; i++) {
543  // An item in the list either specifies a string (local font name) or a URL (remote font to download).
544  CSSFontFaceSrcValueImpl *item = static_cast<CSSFontFaceSrcValueImpl *>(srcList->item(i));
545  CSSFontFaceSource *source = nullptr;
546 
547 #if 0
548  // ENABLE(SVG_FONTS)
549  foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
550 #endif
551 
552  if (!item->isLocal()) {
553  if (item->isSupportedFormat() && m_document) {
554  source = new CSSFontFaceSource(item->resource(), true /*distant*/);
555 #if 0
556  // ENABLE(SVG_FONTS)
557  if (foundSVGFont) {
558  cachedFont->setSVGFont(true);
559  }
560 #endif
561  }
562  } else {
563  source = new CSSFontFaceSource(item->resource());
564  }
565 
566  if (source) {
567 #if 0
568  // ENABLE(SVG_FONTS)
569  source->setSVGFontFaceElement(item->svgFontFaceElement());
570 #endif
571  if (!fontFace) {
572  fontFace = new CSSFontFace(static_cast<FontTraitsMask>(traitsMask), this);
573  }
574  fontFace->addSource(source);
575  }
576  }
577 
578  if (!fontFace || !fontFace->isValid()) {
579  delete fontFace;
580  return;
581  }
582 
583  /*
584  if (rangeList) {
585  unsigned numRanges = rangeList->length();
586  for (unsigned i = 0; i < numRanges; i++) {
587  CSSUnicodeRangeValueImpl* range = static_cast<CSSUnicodeRangeValueImpl*>(rangeList->item(i));
588  fontFace->addRange(range->from(), range->to());
589  }
590  }
591  */
592 
593  // Hash under every single family name.
594  int familyLength = familyList->length();
595  for (int i = 0; i < familyLength; i++) {
596  CSSPrimitiveValueImpl *item = static_cast<CSSPrimitiveValueImpl *>(familyList->item(i));
597  DOMString familyName;
598  if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
599  familyName = DOMString(static_cast<FontFamilyValueImpl *>(item)->fontName());
600  } else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
601  // We need to use the raw text for all the generic family types, since @font-face is a way of actually
602  // defining what font to use for those types.
603  switch (item->getIdent()) {
604  case CSS_VAL_SERIF:
605  familyName = "-khtml-serif";
606  break;
607  case CSS_VAL_SANS_SERIF:
608  familyName = "-khtml-sans-serif";
609  break;
610  case CSS_VAL_CURSIVE:
611  familyName = "-khtml-cursive";
612  break;
613  case CSS_VAL_FANTASY:
614  familyName = "-khtml-fantasy";
615  break;
616  case CSS_VAL_MONOSPACE:
617  familyName = "-khtml-monospace";
618  break;
619  default:
620  break;
621  }
622  }
623 
624  if (familyName.isEmpty()) {
625  continue;
626  }
627 
628  fontFace->addFamilyName(familyName);
629  m_locallyInstalledFontFaces.insertMulti(familyName.lower(), fontFace);
630  fontFace->ref();
631 
632 #if 0
633  // ENABLE(SVG_FONTS)
634  // SVG allows several <font> elements with the same font-family, differing only
635  // in ie. font-variant. Be sure to pick up the right one - in getFontData below.
636  if (foundSVGFont && (traitsMask & FontVariantSmallCapsMask)) {
637  familyName += "-webkit-svg-small-caps";
638  }
639 #endif
640 
641  /*
642  Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName);
643  if (!familyFontFaces) {
644  familyFontFaces = new Vector<RefPtr<CSSFontFace> >;
645  m_fontFaces.set(familyName, familyFontFaces);
646 
647  ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
648  Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces;
649 
650  Vector<unsigned> locallyInstalledFontsTraitsMasks;
651  fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
652  unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size();
653  if (numLocallyInstalledFaces) {
654  familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >;
655  m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces);
656 
657  for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
658  RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]));
659  locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName));
660  ASSERT(locallyInstalledFontFace->isValid());
661  familyLocallyInstalledFaces->append(locallyInstalledFontFace);
662  }
663  }
664  }
665 
666  familyFontFaces->append(fontFace);
667  */
668  }
669 
670  // Should be impossible, but in case empty/invalid family name makes it through...
671  if (fontFace->refCount() < 1) {
672  delete fontFace;
673  }
674 }
675 
676 void CSSFontSelector::requestFamilyName(const DOMString &familyName)
677 {
678  QHash<DOMString, CSSFontFace*>::const_iterator it = m_locallyInstalledFontFaces.constBegin();
679  QHash<DOMString, CSSFontFace*>::const_iterator end = m_locallyInstalledFontFaces.constEnd();
680  if (it == end) {
681  return;
682  }
683  const DOMString familyNameLower = familyName.lower();
684  do {
685  if (it.key() == familyNameLower) {
686  it.value()->refLoaders();
687  }
688  ++it;
689  } while (it != end);
690 }
691 
692 void CSSFontSelector::fontLoaded()
693 {
694  if (!m_document || !m_document->renderer()) {
695  return;
696  }
697  static_cast<khtml::RenderCanvas *>(m_document->renderer())->updateInvalidatedFonts();
698  khtml::Font::markAllCachedFontsAsValid();
699 }
700 
701 void CSSFontSelector::fontCacheInvalidated()
702 {
703  if (!m_document || !m_document->renderer()) {
704  return;
705  }
706  m_document->recalcStyle(DocumentImpl::Force);
707  // m_document->renderer()->setNeedsLayoutAndMinMaxRecalc();
708 }
709 
710 /*
711 static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
712 {
713  if (!document || !document->frame())
714  return 0;
715 
716  const Settings* settings = document->frame()->settings();
717  if (!settings)
718  return 0;
719 
720  AtomicString genericFamily;
721  if (familyName == "-webkit-serif")
722  genericFamily = settings->serifFontFamily();
723  else if (familyName == "-webkit-sans-serif")
724  genericFamily = settings->sansSerifFontFamily();
725  else if (familyName == "-webkit-cursive")
726  genericFamily = settings->cursiveFontFamily();
727  else if (familyName == "-webkit-fantasy")
728  genericFamily = settings->fantasyFontFamily();
729  else if (familyName == "-webkit-monospace")
730  genericFamily = settings->fixedFontFamily();
731  else if (familyName == "-webkit-standard")
732  genericFamily = settings->standardFontFamily();
733 
734  if (!genericFamily.isEmpty())
735  return fontCache()->getCachedFontData(fontCache()->getCachedFontPlatformData(fontDescription, genericFamily));
736 
737  return 0;
738 }
739 */
740 static FontTraitsMask desiredTraitsMaskForComparison;
741 
742 static inline bool compareFontFaces(CSSFontFace *first, CSSFontFace *second)
743 {
744  FontTraitsMask firstTraitsMask = first->traitsMask();
745  FontTraitsMask secondTraitsMask = second->traitsMask();
746 
747  bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
748  bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
749 
750  if (firstHasDesiredVariant != secondHasDesiredVariant) {
751  return firstHasDesiredVariant;
752  }
753 
754  bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
755  bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
756 
757  if (firstHasDesiredStyle != secondHasDesiredStyle) {
758  return firstHasDesiredStyle;
759  }
760 
761  if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) {
762  return false;
763  }
764  if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) {
765  return true;
766  }
767 
768  // https://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#q46 says: "If there are fewer then 9 weights in the family, the default algorithm
769  // for filling the "holes" is as follows. If '500' is unassigned, it will be assigned the same font as '400'. If any of the values '600',
770  // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
771  // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
772  // or the next darker otherwise."
773  // For '400', we made up our own rule (which then '500' follows).
774 
775  static const unsigned fallbackRuleSets = 9;
776  static const unsigned rulesPerSet = 8;
777  static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
778  { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
779  { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
780  { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
781  { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
782  { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
783  { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
784  { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
785  { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
786  { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
787  };
788 
789  unsigned ruleSetIndex = 0;
790  unsigned w = FontWeight100Bit;
791  while (!(desiredTraitsMaskForComparison & (1 << w))) {
792  w++;
793  ruleSetIndex++;
794  }
795 
796  assert(ruleSetIndex < fallbackRuleSets);
797  const FontTraitsMask *weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
798  for (unsigned i = 0; i < rulesPerSet; ++i) {
799  if (secondTraitsMask & weightFallbackRule[i]) {
800  return false;
801  }
802  if (firstTraitsMask & weightFallbackRule[i]) {
803  return true;
804  }
805  }
806 
807  return false;
808 }
809 
810 /*
811 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
812 {
813  if (m_fontFaces.isEmpty()) {
814  if (familyName.startsWith("-khtml-"))
815  return fontDataForGenericFamily(m_document, fontDescription, familyName);
816  return 0;
817  }
818 
819  String family = familyName.string();
820 
821 #if 0
822  // ENABLE(SVG_FONTS)
823  if (fontDescription.smallCaps())
824  family += "-khtml-svg-small-caps";
825 #endif
826 
827  Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
828  // If no face was found, then return 0 and let the OS come up with its best match for the name.
829  if (!familyFontFaces || familyFontFaces->isEmpty()) {
830  // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
831  // settings.
832  return fontDataForGenericFamily(m_document, fontDescription, familyName);
833  }
834 
835  HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family);
836  if (!segmentedFontFaceCache) {
837  segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >;
838  m_fonts.set(family, segmentedFontFaceCache);
839  }
840 
841  FontTraitsMask traitsMask = fontDescription.traitsMask();
842 
843  RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask);
844 
845  if (!face) {
846  face = CSSSegmentedFontFace::create(this);
847  segmentedFontFaceCache->set(traitsMask, face);
848  // Collect all matching faces and sort them in order of preference.
849  Vector<CSSFontFace*, 32> candidateFontFaces;
850  for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
851  CSSFontFace* candidate = familyFontFaces->at(i).get();
852  unsigned candidateTraitsMask = candidate->traitsMask();
853  if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
854  continue;
855  if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
856  continue;
857  candidateFontFaces.append(candidate);
858  }
859 
860  if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
861  unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
862  for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
863  CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
864  unsigned candidateTraitsMask = candidate->traitsMask();
865  if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
866  continue;
867  if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
868  continue;
869  candidateFontFaces.append(candidate);
870  }
871  }
872 
873  desiredTraitsMaskForComparison = traitsMask;
874  std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
875  unsigned numCandidates = candidateFontFaces.size();
876  for (unsigned i = 0; i < numCandidates; ++i)
877  face->appendFontFace(candidateFontFaces[i]);
878  }
879 
880  // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over.
881  return face->getFontData(fontDescription);
882 }
883 */
884 
885 }
DOMString lower() const
Returns a lowercase version of the string.
Definition: dom_string.cpp:232
int addApplicationFontFromData(const QByteArray &fontData)
void removeSubstitutions(const QString &familyName)
QStringList applicationFontFamilies(int id)
bool removeApplicationFont(int id)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
if(recurs()&&!first)
This library provides a full-featured HTML parser and widget.
const QList< QKeySequence > & end()
bool isValid(QStringView ifopt)
void insertSubstitution(const QString &familyName, const QString &substituteName)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:51 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.