• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4  * Copyright (C) 2013 Google Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "config.h"
24 #include "core/css/resolver/FontBuilder.h"
25 
26 #include "core/css/CSSCalculationValue.h"
27 #include "core/css/CSSToLengthConversionData.h"
28 #include "core/frame/LocalFrame.h"
29 #include "core/frame/Settings.h"
30 #include "core/rendering/RenderTheme.h"
31 #include "core/rendering/RenderView.h"
32 #include "core/rendering/TextAutosizer.h"
33 #include "platform/fonts/FontDescription.h"
34 #include "platform/text/LocaleToScriptMapping.h"
35 
36 namespace blink {
37 
38 // FIXME: This scoping class is a short-term fix to minimize the changes in
39 // Font-constructing logic.
40 class FontDescriptionChangeScope {
41     STACK_ALLOCATED();
42 public:
FontDescriptionChangeScope(FontBuilder * fontBuilder)43     FontDescriptionChangeScope(FontBuilder* fontBuilder)
44         : m_fontBuilder(fontBuilder)
45         , m_fontDescription(fontBuilder->m_style->fontDescription())
46     {
47     }
48 
reset()49     void reset() { m_fontDescription = FontDescription(); }
set(const FontDescription & fontDescription)50     void set(const FontDescription& fontDescription) { m_fontDescription = fontDescription; }
fontDescription()51     FontDescription& fontDescription() { return m_fontDescription; }
52 
~FontDescriptionChangeScope()53     ~FontDescriptionChangeScope()
54     {
55         m_fontBuilder->didChangeFontParameters(m_fontBuilder->m_style->setFontDescription(m_fontDescription));
56     }
57 
58 private:
59     RawPtrWillBeMember<FontBuilder> m_fontBuilder;
60     FontDescription m_fontDescription;
61 };
62 
FontBuilder()63 FontBuilder::FontBuilder()
64     : m_document(nullptr)
65     , m_style(0)
66     , m_fontDirty(false)
67 {
68 }
69 
initForStyleResolve(const Document & document,RenderStyle * style)70 void FontBuilder::initForStyleResolve(const Document& document, RenderStyle* style)
71 {
72     ASSERT(document.frame());
73     m_document = &document;
74     m_style = style;
75     m_fontDirty = false;
76 }
77 
setFontFamilyToStandard(FontDescription & fontDescription,const Document * document)78 inline static void setFontFamilyToStandard(FontDescription& fontDescription, const Document* document)
79 {
80     if (!document || !document->settings())
81         return;
82 
83     fontDescription.setGenericFamily(FontDescription::StandardFamily);
84     const AtomicString& standardFontFamily = document->settings()->genericFontFamilySettings().standard();
85     if (standardFontFamily.isEmpty())
86         return;
87 
88     fontDescription.firstFamily().setFamily(standardFontFamily);
89     // FIXME: Why is this needed here?
90     fontDescription.firstFamily().appendFamily(nullptr);
91 }
92 
setInitial(float effectiveZoom)93 void FontBuilder::setInitial(float effectiveZoom)
94 {
95     ASSERT(m_document && m_document->settings());
96     if (!m_document || !m_document->settings())
97         return;
98 
99     FontDescriptionChangeScope scope(this);
100 
101     scope.reset();
102     setFontFamilyToStandard(scope.fontDescription(), m_document);
103     setSize(scope.fontDescription(), FontBuilder::initialSize());
104 }
105 
inheritFrom(const FontDescription & fontDescription)106 void FontBuilder::inheritFrom(const FontDescription& fontDescription)
107 {
108     FontDescriptionChangeScope scope(this);
109 
110     scope.set(fontDescription);
111 }
112 
didChangeFontParameters(bool changed)113 void FontBuilder::didChangeFontParameters(bool changed)
114 {
115     m_fontDirty |= changed;
116 }
117 
fromSystemFont(CSSValueID valueId,float effectiveZoom)118 void FontBuilder::fromSystemFont(CSSValueID valueId, float effectiveZoom)
119 {
120     FontDescriptionChangeScope scope(this);
121 
122     FontDescription fontDescription;
123     RenderTheme::theme().systemFont(valueId, fontDescription);
124 
125     // Double-check and see if the theme did anything. If not, don't bother updating the font.
126     if (!fontDescription.isAbsoluteSize())
127         return;
128 
129     // Make sure the rendering mode and printer font settings are updated.
130     const Settings* settings = m_document->settings();
131     ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
132     if (!settings)
133         return;
134 
135     // Handle the zoom factor.
136     fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, fontDescription.specifiedSize()));
137     scope.set(fontDescription);
138 }
139 
setFontFamilyInitial()140 void FontBuilder::setFontFamilyInitial()
141 {
142     FontDescriptionChangeScope scope(this);
143 
144     setFontFamilyToStandard(scope.fontDescription(), m_document);
145 }
146 
setFontFamilyInherit(const FontDescription & parentFontDescription)147 void FontBuilder::setFontFamilyInherit(const FontDescription& parentFontDescription)
148 {
149     FontDescriptionChangeScope scope(this);
150 
151     scope.fontDescription().setGenericFamily(parentFontDescription.genericFamily());
152     scope.fontDescription().setFamily(parentFontDescription.family());
153 }
154 
155 // FIXME: I am not convinced FontBuilder needs to know anything about CSSValues.
setFontFamilyValue(CSSValue * value)156 void FontBuilder::setFontFamilyValue(CSSValue* value)
157 {
158     FontDescriptionChangeScope scope(this);
159 
160     if (!value->isValueList())
161         return;
162 
163     FontFamily& firstFamily = scope.fontDescription().firstFamily();
164     FontFamily* currFamily = 0;
165 
166     // Before mapping in a new font-family property, we should reset the generic family.
167     FixedPitchFontType oldFixedPitchFontType = scope.fontDescription().fixedPitchFontType();
168     scope.fontDescription().setGenericFamily(FontDescription::NoFamily);
169 
170     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
171         CSSValue* item = i.value();
172         if (!item->isPrimitiveValue())
173             continue;
174         CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
175         AtomicString face;
176         Settings* settings = m_document->settings();
177         if (contentValue->isString()) {
178             face = AtomicString(contentValue->getStringValue());
179         } else if (settings) {
180             switch (contentValue->getValueID()) {
181             case CSSValueWebkitBody:
182                 face = settings->genericFontFamilySettings().standard();
183                 break;
184             case CSSValueSerif:
185                 face = FontFamilyNames::webkit_serif;
186                 scope.fontDescription().setGenericFamily(FontDescription::SerifFamily);
187                 break;
188             case CSSValueSansSerif:
189                 face = FontFamilyNames::webkit_sans_serif;
190                 scope.fontDescription().setGenericFamily(FontDescription::SansSerifFamily);
191                 break;
192             case CSSValueCursive:
193                 face = FontFamilyNames::webkit_cursive;
194                 scope.fontDescription().setGenericFamily(FontDescription::CursiveFamily);
195                 break;
196             case CSSValueFantasy:
197                 face = FontFamilyNames::webkit_fantasy;
198                 scope.fontDescription().setGenericFamily(FontDescription::FantasyFamily);
199                 break;
200             case CSSValueMonospace:
201                 face = FontFamilyNames::webkit_monospace;
202                 scope.fontDescription().setGenericFamily(FontDescription::MonospaceFamily);
203                 break;
204             case CSSValueWebkitPictograph:
205                 face = FontFamilyNames::webkit_pictograph;
206                 scope.fontDescription().setGenericFamily(FontDescription::PictographFamily);
207                 break;
208             default:
209                 break;
210             }
211         }
212 
213         if (!face.isEmpty()) {
214             if (!currFamily) {
215                 // Filling in the first family.
216                 firstFamily.setFamily(face);
217                 firstFamily.appendFamily(nullptr); // Remove any inherited family-fallback list.
218                 currFamily = &firstFamily;
219             } else {
220                 RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
221                 newFamily->setFamily(face);
222                 currFamily->appendFamily(newFamily);
223                 currFamily = newFamily.get();
224             }
225         }
226     }
227 
228     // We can't call useFixedDefaultSize() until all new font families have been added
229     // If currFamily is non-zero then we set at least one family on this description.
230     if (!currFamily)
231         return;
232 
233     if (scope.fontDescription().keywordSize() && scope.fontDescription().fixedPitchFontType() != oldFixedPitchFontType)
234         setSize(scope.fontDescription(), FontDescription::Size(scope.fontDescription().keywordSize(), 0.0f, false));
235 }
236 
setWeight(FontWeight fontWeight)237 void FontBuilder::setWeight(FontWeight fontWeight)
238 {
239     FontDescriptionChangeScope scope(this);
240 
241     scope.fontDescription().setWeight(fontWeight);
242 }
243 
setSize(const FontDescription::Size & size)244 void FontBuilder::setSize(const FontDescription::Size& size)
245 {
246     FontDescriptionChangeScope scope(this);
247 
248     setSize(scope.fontDescription(), size);
249 }
250 
setStretch(FontStretch fontStretch)251 void FontBuilder::setStretch(FontStretch fontStretch)
252 {
253     FontDescriptionChangeScope scope(this);
254 
255     scope.fontDescription().setStretch(fontStretch);
256 }
257 
setScript(const String & locale)258 void FontBuilder::setScript(const String& locale)
259 {
260     FontDescriptionChangeScope scope(this);
261 
262     scope.fontDescription().setLocale(locale);
263     scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale));
264 }
265 
setStyle(FontStyle italic)266 void FontBuilder::setStyle(FontStyle italic)
267 {
268     FontDescriptionChangeScope scope(this);
269 
270     scope.fontDescription().setStyle(italic);
271 }
272 
setVariant(FontVariant smallCaps)273 void FontBuilder::setVariant(FontVariant smallCaps)
274 {
275     FontDescriptionChangeScope scope(this);
276 
277     scope.fontDescription().setVariant(smallCaps);
278 }
279 
setVariantLigatures(const FontDescription::VariantLigatures & ligatures)280 void FontBuilder::setVariantLigatures(const FontDescription::VariantLigatures& ligatures)
281 {
282     FontDescriptionChangeScope scope(this);
283 
284     scope.fontDescription().setVariantLigatures(ligatures);
285 }
286 
setTextRendering(TextRenderingMode textRenderingMode)287 void FontBuilder::setTextRendering(TextRenderingMode textRenderingMode)
288 {
289     FontDescriptionChangeScope scope(this);
290 
291     scope.fontDescription().setTextRendering(textRenderingMode);
292 }
293 
setKerning(FontDescription::Kerning kerning)294 void FontBuilder::setKerning(FontDescription::Kerning kerning)
295 {
296     FontDescriptionChangeScope scope(this);
297 
298     scope.fontDescription().setKerning(kerning);
299 }
300 
setFontSmoothing(FontSmoothingMode foontSmoothingMode)301 void FontBuilder::setFontSmoothing(FontSmoothingMode foontSmoothingMode)
302 {
303     FontDescriptionChangeScope scope(this);
304 
305     scope.fontDescription().setFontSmoothing(foontSmoothingMode);
306 }
307 
setFeatureSettings(PassRefPtr<FontFeatureSettings> settings)308 void FontBuilder::setFeatureSettings(PassRefPtr<FontFeatureSettings> settings)
309 {
310     FontDescriptionChangeScope scope(this);
311 
312     scope.fontDescription().setFeatureSettings(settings);
313 }
314 
setSize(FontDescription & fontDescription,const FontDescription::Size & size)315 void FontBuilder::setSize(FontDescription& fontDescription, const FontDescription::Size& size)
316 {
317     float specifiedSize = size.value;
318 
319     if (!specifiedSize && size.keyword)
320         specifiedSize = FontSize::fontSizeForKeyword(m_document, size.keyword, fontDescription.fixedPitchFontType());
321 
322     if (specifiedSize < 0)
323         return;
324 
325     // Overly large font sizes will cause crashes on some platforms (such as Windows).
326     // Cap font size here to make sure that doesn't happen.
327     specifiedSize = std::min(maximumAllowedFontSize, specifiedSize);
328 
329     fontDescription.setKeywordSize(size.keyword);
330     fontDescription.setSpecifiedSize(specifiedSize);
331     fontDescription.setIsAbsoluteSize(size.isAbsolute);
332 }
333 
getComputedSizeFromSpecifiedSize(FontDescription & fontDescription,float effectiveZoom,float specifiedSize)334 float FontBuilder::getComputedSizeFromSpecifiedSize(FontDescription& fontDescription, float effectiveZoom, float specifiedSize)
335 {
336     float zoomFactor = effectiveZoom;
337     // FIXME: Why is this here!!!!?!
338     if (LocalFrame* frame = m_document->frame())
339         zoomFactor *= frame->textZoomFactor();
340 
341     return FontSize::getComputedSizeFromSpecifiedSize(m_document, zoomFactor, fontDescription.isAbsoluteSize(), specifiedSize);
342 }
343 
getFontAndGlyphOrientation(const RenderStyle * style,FontOrientation & fontOrientation,NonCJKGlyphOrientation & glyphOrientation)344 static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation)
345 {
346     if (style->isHorizontalWritingMode()) {
347         fontOrientation = Horizontal;
348         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
349         return;
350     }
351 
352     switch (style->textOrientation()) {
353     case TextOrientationVerticalRight:
354         fontOrientation = Vertical;
355         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
356         return;
357     case TextOrientationUpright:
358         fontOrientation = Vertical;
359         glyphOrientation = NonCJKGlyphOrientationUpright;
360         return;
361     case TextOrientationSideways:
362         if (style->writingMode() == LeftToRightWritingMode) {
363             // FIXME: This should map to sideways-left, which is not supported yet.
364             fontOrientation = Vertical;
365             glyphOrientation = NonCJKGlyphOrientationVerticalRight;
366             return;
367         }
368         fontOrientation = Horizontal;
369         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
370         return;
371     case TextOrientationSidewaysRight:
372         fontOrientation = Horizontal;
373         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
374         return;
375     default:
376         ASSERT_NOT_REACHED();
377         fontOrientation = Horizontal;
378         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
379         return;
380     }
381 }
382 
checkForOrientationChange(RenderStyle * style)383 void FontBuilder::checkForOrientationChange(RenderStyle* style)
384 {
385     FontOrientation fontOrientation;
386     NonCJKGlyphOrientation glyphOrientation;
387     getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation);
388 
389     FontDescriptionChangeScope scope(this);
390 
391     if (scope.fontDescription().orientation() == fontOrientation && scope.fontDescription().nonCJKGlyphOrientation() == glyphOrientation)
392         return;
393 
394     scope.fontDescription().setNonCJKGlyphOrientation(glyphOrientation);
395     scope.fontDescription().setOrientation(fontOrientation);
396 }
397 
checkForGenericFamilyChange(RenderStyle * style,const RenderStyle * parentStyle)398 void FontBuilder::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle)
399 {
400     FontDescriptionChangeScope scope(this);
401 
402     if (scope.fontDescription().isAbsoluteSize() || !parentStyle)
403         return;
404 
405     const FontDescription& parentFontDescription = parentStyle->fontDescription();
406     if (scope.fontDescription().fixedPitchFontType() == parentFontDescription.fixedPitchFontType())
407         return;
408 
409     // For now, lump all families but monospace together.
410     if (scope.fontDescription().genericFamily() != FontDescription::MonospaceFamily
411         && parentFontDescription.genericFamily() != FontDescription::MonospaceFamily)
412         return;
413 
414     // We know the parent is monospace or the child is monospace, and that font
415     // size was unspecified. We want to scale our font size as appropriate.
416     // If the font uses a keyword size, then we refetch from the table rather than
417     // multiplying by our scale factor.
418     float size;
419     if (scope.fontDescription().keywordSize()) {
420         size = FontSize::fontSizeForKeyword(m_document, scope.fontDescription().keywordSize(), scope.fontDescription().fixedPitchFontType());
421     } else {
422         Settings* settings = m_document->settings();
423         float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
424             ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
425             : 1;
426         size = parentFontDescription.fixedPitchFontType() == FixedPitchFont ?
427             scope.fontDescription().specifiedSize() / fixedScaleFactor :
428             scope.fontDescription().specifiedSize() * fixedScaleFactor;
429     }
430 
431     scope.fontDescription().setSpecifiedSize(size);
432     updateComputedSize(scope.fontDescription(), style);
433 }
434 
updateComputedSize(RenderStyle * style,const RenderStyle * parentStyle)435 void FontBuilder::updateComputedSize(RenderStyle* style, const RenderStyle* parentStyle)
436 {
437     FontDescriptionChangeScope scope(this);
438     updateComputedSize(scope.fontDescription(), style);
439 }
440 
updateComputedSize(FontDescription & fontDescription,RenderStyle * style)441 void FontBuilder::updateComputedSize(FontDescription& fontDescription, RenderStyle* style)
442 {
443     float computedSize = getComputedSizeFromSpecifiedSize(fontDescription, style->effectiveZoom(), fontDescription.specifiedSize());
444     float multiplier = style->textAutosizingMultiplier();
445     if (multiplier > 1)
446         computedSize = TextAutosizer::computeAutosizedFontSize(computedSize, multiplier);
447     fontDescription.setComputedSize(computedSize);
448 }
449 
450 // FIXME: style param should come first
createFont(PassRefPtrWillBeRawPtr<FontSelector> fontSelector,const RenderStyle * parentStyle,RenderStyle * style)451 void FontBuilder::createFont(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style)
452 {
453     if (!m_fontDirty)
454         return;
455 
456     updateComputedSize(style, parentStyle);
457     checkForGenericFamilyChange(style, parentStyle);
458     checkForOrientationChange(style);
459     style->font().update(fontSelector);
460     m_fontDirty = false;
461 }
462 
createFontForDocument(PassRefPtrWillBeRawPtr<FontSelector> fontSelector,RenderStyle * documentStyle)463 void FontBuilder::createFontForDocument(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, RenderStyle* documentStyle)
464 {
465     FontDescription fontDescription = FontDescription();
466     fontDescription.setLocale(documentStyle->locale());
467     fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
468 
469     setFontFamilyToStandard(fontDescription, m_document);
470 
471     setSize(fontDescription, FontDescription::Size(FontSize::initialKeywordSize(), 0.0f, false));
472     updateComputedSize(fontDescription, documentStyle);
473 
474     FontOrientation fontOrientation;
475     NonCJKGlyphOrientation glyphOrientation;
476     getFontAndGlyphOrientation(documentStyle, fontOrientation, glyphOrientation);
477     fontDescription.setOrientation(fontOrientation);
478     fontDescription.setNonCJKGlyphOrientation(glyphOrientation);
479     documentStyle->setFontDescription(fontDescription);
480     documentStyle->font().update(fontSelector);
481 }
482 
483 }
484